* [PATCH 01/28] mISDN: Fix NULL pointer bug in if-condition of mISDN_dsp
From: Karsten Keil @ 2012-03-17 9:27 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <jolly@eversberg.eu>
Fix bug in cases where dsp->conf was NULL.
Signed-off-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/mISDN/dsp_cmx.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index 334feab..b7589c2 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -1328,7 +1328,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
}
if (dsp->conf && dsp->conf->software && dsp->conf->hardware)
tx_data_only = 1;
- if (dsp->conf->software && dsp->echo.hardware)
+ if (dsp->echo.software && dsp->echo.hardware)
tx_data_only = 1;
}
--
1.7.3.4
^ permalink raw reply related
* [PATCH 04/28] mISDN: Added PH_* state info to tei manager.
From: Karsten Keil @ 2012-03-17 9:38 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <andreas@eversberg.eu>
Tei manager reports current layer 1 state on creation.
On state change it reports it to the socket interface.
Signed-off-by: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/mISDN/tei.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index ba2bc0c..969766f 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -1023,6 +1023,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq)
mgr->up = crq->ch;
id = DL_INFO_L2_CONNECT;
teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id);
+ if (test_bit(MGR_PH_ACTIVE, &mgr->options))
+ teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
crq->ch = NULL;
if (!list_empty(&mgr->layer2)) {
read_lock_irqsave(&mgr->lock, flags);
@@ -1096,12 +1098,16 @@ mgr_send(struct mISDNchannel *ch, struct sk_buff *skb)
break;
case PH_ACTIVATE_IND:
test_and_set_bit(MGR_PH_ACTIVE, &mgr->options);
+ if (mgr->up)
+ teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL);
do_send(mgr);
ret = 0;
break;
case PH_DEACTIVATE_IND:
test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options);
+ if (mgr->up)
+ teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL);
mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL);
ret = 0;
break;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 14/28] mISDN: Layer1 statemachine fix
From: Karsten Keil @ 2012-03-17 15:07 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
The timer3 and the activation delay timer need to be
independent.
Now layer1 pass TBR3 again.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/layer1.c | 23 ++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c
index 65912bd..7feb78a 100644
--- a/drivers/isdn/mISDN/layer1.c
+++ b/drivers/isdn/mISDN/layer1.c
@@ -28,7 +28,8 @@ static u_int *debug;
struct layer1 {
u_long Flags;
struct FsmInst l1m;
- struct FsmTimer timer;
+ struct FsmTimer timer3;
+ struct FsmTimer timerX;
int delay;
int t3_value;
struct dchannel *dch;
@@ -135,7 +136,7 @@ l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
struct layer1 *l1 = fi->userdata;
mISDN_FsmChangeState(fi, ST_L1_F3);
- mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
+ mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2);
test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);
}
@@ -180,11 +181,11 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg)
mISDN_FsmChangeState(fi, ST_L1_F7);
l1->dcb(l1->dch, INFO3_P8);
if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags))
- mISDN_FsmDelTimer(&l1->timer, 4);
+ mISDN_FsmDelTimer(&l1->timerX, 4);
if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) {
if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags))
- mISDN_FsmDelTimer(&l1->timer, 3);
- mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2);
+ mISDN_FsmDelTimer(&l1->timer3, 3);
+ mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2);
test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags);
}
}
@@ -201,8 +202,9 @@ l1_timer3(struct FsmInst *fi, int event, void *arg)
l1->dcb(l1->dch, PH_DEACTIVATE_IND);
}
if (l1->l1m.state != ST_L1_F6) {
+ /* keep in F6 */
mISDN_FsmChangeState(fi, ST_L1_F3);
- l1->dcb(l1->dch, HW_POWERUP_REQ);
+ /* do not force anything here, we need send INFO 0 */
}
}
@@ -234,8 +236,9 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg)
{
struct layer1 *l1 = fi->userdata;
- mISDN_FsmRestartTimer(&l1->timer, l1->t3_value, EV_TIMER3, NULL, 2);
+ mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
+ /* Tell HW to send INFO 1 */
l1->dcb(l1->dch, HW_RESET_REQ);
}
@@ -303,7 +306,8 @@ static struct FsmNode L1SFnList[] =
static void
release_l1(struct layer1 *l1) {
- mISDN_FsmDelTimer(&l1->timer, 0);
+ mISDN_FsmDelTimer(&l1->timerX, 0);
+ mISDN_FsmDelTimer(&l1->timer3, 0);
if (l1->dch)
l1->dch->l1 = NULL;
module_put(THIS_MODULE);
@@ -395,7 +399,8 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) {
nl1->l1m.printdebug = l1m_debug;
nl1->dch = dch;
nl1->dcb = dcb;
- mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer);
+ mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3);
+ mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX);
__module_get(THIS_MODULE);
dch->l1 = nl1;
return 0;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 12/28] mISDN: L2 timeouts need to be queued as L2 event
From: Karsten Keil @ 2012-03-17 15:01 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
To be full preemptiv safe, we cannot handle a L2 timeout in
the timer context itself, we should do all actions via
the D-channel thread.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/layer2.c | 58 +++++++++++++++++++++++++++++++++++++++---
drivers/isdn/mISDN/tei.c | 13 +++++++--
include/linux/mISDNif.h | 9 ++++++-
3 files changed, 71 insertions(+), 9 deletions(-)
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index 39d7375..d421495 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -58,6 +58,8 @@ enum {
EV_L1_DEACTIVATE,
EV_L2_T200,
EV_L2_T203,
+ EV_L2_T200I,
+ EV_L2_T203I,
EV_L2_SET_OWN_BUSY,
EV_L2_CLEAR_OWN_BUSY,
EV_L2_FRAME_ERROR,
@@ -86,6 +88,8 @@ static char *strL2Event[] =
"EV_L1_DEACTIVATE",
"EV_L2_T200",
"EV_L2_T203",
+ "EV_L2_T200I",
+ "EV_L2_T203I",
"EV_L2_SET_OWN_BUSY",
"EV_L2_CLEAR_OWN_BUSY",
"EV_L2_FRAME_ERROR",
@@ -276,6 +280,31 @@ ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) {
return ret;
}
+static void
+l2_timeout(struct FsmInst *fi, int event, void *arg)
+{
+ struct layer2 *l2 = fi->userdata;
+ struct sk_buff *skb;
+ struct mISDNhead *hh;
+
+ skb = mI_alloc_skb(0, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_WARNING "L2(%d,%d) nr:%x timer %s lost - no skb\n",
+ l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
+ "T200" : "T203");
+ return;
+ }
+ hh = mISDN_HEAD_P(skb);
+ hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
+ hh->id = l2->ch.nr;
+ if (*debug & DEBUG_TIMER)
+ printk(KERN_DEBUG "L2(%d,%d) nr:%x timer %s expired\n",
+ l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
+ "T200" : "T203");
+ if (l2->ch.st)
+ l2->ch.st->own.recv(&l2->ch.st->own, skb);
+}
+
static int
l2mgr(struct layer2 *l2, u_int prim, void *arg) {
long c = (long)arg;
@@ -1814,11 +1843,16 @@ static struct FsmNode L2FnList[] =
{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
{ST_L2_7, EV_L2_I, l2_got_iframe},
{ST_L2_8, EV_L2_I, l2_got_iframe},
- {ST_L2_5, EV_L2_T200, l2_st5_tout_200},
- {ST_L2_6, EV_L2_T200, l2_st6_tout_200},
- {ST_L2_7, EV_L2_T200, l2_st7_tout_200},
- {ST_L2_8, EV_L2_T200, l2_st8_tout_200},
- {ST_L2_7, EV_L2_T203, l2_st7_tout_203},
+ {ST_L2_5, EV_L2_T200, l2_timeout},
+ {ST_L2_6, EV_L2_T200, l2_timeout},
+ {ST_L2_7, EV_L2_T200, l2_timeout},
+ {ST_L2_8, EV_L2_T200, l2_timeout},
+ {ST_L2_7, EV_L2_T203, l2_timeout},
+ {ST_L2_5, EV_L2_T200I, l2_st5_tout_200},
+ {ST_L2_6, EV_L2_T200I, l2_st6_tout_200},
+ {ST_L2_7, EV_L2_T200I, l2_st7_tout_200},
+ {ST_L2_8, EV_L2_T200I, l2_st8_tout_200},
+ {ST_L2_7, EV_L2_T203I, l2_st7_tout_203},
{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
@@ -1932,6 +1966,14 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
if (*debug & DEBUG_L2_RECV)
printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n",
__func__, hh->prim, hh->id, l2->sapi, l2->tei);
+ if (hh->prim == DL_INTERN_MSG) {
+ struct mISDNhead *chh = hh + 1; /* saved copy */
+
+ *hh = *chh;
+ if (*debug & DEBUG_L2_RECV)
+ printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
+ __func__, hh->prim, hh->id);
+ }
switch (hh->prim) {
case PH_DATA_IND:
ret = ph_data_indication(l2, hh, skb);
@@ -1987,6 +2029,12 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ,
skb);
break;
+ case DL_TIMER200_IND:
+ mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL);
+ break;
+ case DL_TIMER203_IND:
+ mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL);
+ break;
default:
if (*debug & DEBUG_L2)
l2m_debug(&l2->l2m, "l2 unknown pr %04x",
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 25ed826..c7f6bea 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -1293,7 +1293,7 @@ static int
mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
{
struct manager *mgr = container_of(ch, struct manager, bcast);
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb);
struct sk_buff *cskb = NULL;
struct layer2 *l2;
u_long flags;
@@ -1308,10 +1308,17 @@ mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
skb = NULL;
} else {
if (!cskb)
- cskb = skb_copy(skb, GFP_KERNEL);
+ cskb = skb_copy(skb, GFP_ATOMIC);
}
if (cskb) {
- ret = l2->ch.send(&l2->ch, cskb);
+ hhc = mISDN_HEAD_P(cskb);
+ /* save original header behind normal header */
+ hhc++;
+ *hhc = *hh;
+ hhc--;
+ hhc->prim = DL_INTERN_MSG;
+ hhc->id = l2->ch.nr;
+ ret = ch->st->own.recv(&ch->st->own, cskb);
if (ret) {
if (*debug & DEBUG_SEND_ERR)
printk(KERN_DEBUG
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index bdda647..b7457e8 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 24
+#define MISDN_RELEASE 26
/* primitives for information exchange
* generell format
@@ -115,6 +115,11 @@
#define MDL_ERROR_IND 0x1F04
#define MDL_ERROR_RSP 0x5F04
+/* intern layer 2 */
+#define DL_TIMER200_IND 0x7004
+#define DL_TIMER203_IND 0x7304
+#define DL_INTERN_MSG 0x7804
+
/* DL_INFORMATION_IND types */
#define DL_INFO_L2_CONNECT 0x0001
#define DL_INFO_L2_REMOVED 0x0002
@@ -289,6 +294,8 @@ struct mISDNversion {
unsigned short release;
};
+#define MAX_DEVICE_ID 63
+
struct mISDN_devinfo {
u_int id;
u_int Dprotocols;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 07/28] mISDN: Added support for fragmentation of E1 interfaces of hfcmulti driver.
From: Karsten Keil @ 2012-03-17 10:01 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <jolly@eversberg.eu>
Fragmentation is usefull if multiple devices are connected to an E1
interface. Each fragment will have a subset of the available timeslots.
These devices require a cascde connection or a multiplexer.
Signed-off-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfc_multi.h | 6 +-
drivers/isdn/hardware/mISDN/hfcmulti.c | 396 ++++++++++++++++++-------------
2 files changed, 236 insertions(+), 166 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h
index 09e4e77..c601f88 100644
--- a/drivers/isdn/hardware/mISDN/hfc_multi.h
+++ b/drivers/isdn/hardware/mISDN/hfc_multi.h
@@ -208,7 +208,10 @@ 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_tx; /* if there is data TX / RX */
u_int activity_rx; /* bitmask according to port number */
/* (will be cleared after */
@@ -234,7 +237,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 876f7d0..4301331 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 */
@@ -1619,9 +1634,9 @@ hfcmulti_leds(struct hfc_multi *hc)
led[1] = 0;
led[2] = 0;
led[3] = 0;
- dch = hc->chan[hc->dslot].dch;
+ dch = hc->chan[hc->dnum[0]].dch;
if (dch) {
- if (hc->chan[hc->dslot].los)
+ if (hc->chan[hc->dnum[0]].los)
led[1] = 1;
if (hc->e1_state != 1) {
led[0] = 1;
@@ -2453,55 +2468,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)
@@ -2510,10 +2525,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;
@@ -2524,7 +2539,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:
@@ -2535,7 +2550,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:
@@ -2545,7 +2560,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);
@@ -2555,7 +2570,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;
}
@@ -2696,7 +2711,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) {
@@ -2771,7 +2786,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) {
@@ -2781,23 +2796,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);
}
@@ -3870,31 +3888,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 {
@@ -3907,12 +3931,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) {
@@ -3975,13 +3999,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;
@@ -3992,8 +4017,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 */
@@ -4571,6 +4594,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
@@ -4626,7 +4651,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);
@@ -4648,15 +4674,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)
@@ -4667,15 +4697,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)
@@ -4693,61 +4719,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) {
@@ -4763,7 +4737,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 */
@@ -4773,7 +4747,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) {
@@ -4782,7 +4756,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) {
@@ -4792,7 +4766,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) {
@@ -4802,7 +4776,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)) {
@@ -4811,7 +4785,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"
@@ -4843,20 +4817,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);
+ 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);
@@ -4989,7 +5028,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",
@@ -5023,18 +5063,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;
@@ -5117,23 +5175,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 */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 02/28] mISDN: Fixed hardware bridging/conference check routine of mISDN_dsp.ko.
From: Karsten Keil @ 2012-03-17 9:29 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <jolly@eversberg.eu>
In come cases the hardware bridging/conference (2-n parties) was selected,
but still pure software bridging/conference was used.
Signed-off-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/mISDN/dsp_cmx.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index b7589c2..0c104b9 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -742,8 +742,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
member->dsp->pcm_slot_tx,
member->dsp->pcm_bank_tx,
member->dsp->pcm_bank_rx);
- conf->hardware = 0;
- conf->software = 1;
+ conf->hardware = 1;
+ conf->software = tx_data;
return;
}
/* find a new slot */
@@ -834,8 +834,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
nextm->dsp->name,
member->dsp->pcm_slot_tx,
member->dsp->pcm_slot_rx);
- conf->hardware = 0;
- conf->software = 1;
+ conf->hardware = 1;
+ conf->software = tx_data;
return;
}
/* find two new slot */
@@ -939,8 +939,11 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
/* for more than two members.. */
/* if all members already have the same conference */
- if (all_conf)
+ if (all_conf) {
+ conf->hardware = 1;
+ conf->software = tx_data;
return;
+ }
/*
* if there is an existing conference, but not all members have joined
@@ -1013,6 +1016,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
dsp_cmx_hw_message(member->dsp,
MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0);
}
+ conf->hardware = 1;
+ conf->software = tx_data;
return;
}
--
1.7.3.4
^ permalink raw reply related
* [PATCH 10/28] mISDN: Add interface for PCM only access
From: Karsten Keil @ 2012-03-17 14:54 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Sometimes the ISDN chip only control the D-channel
and B-channel are only accessed via the PCM interface.
Add infrastruckture for this mode.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/socket.c | 1 +
include/linux/mISDNhw.h | 3 +++
include/linux/mISDNif.h | 13 +++++++++----
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index abe2d69..1254d8d 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -544,6 +544,7 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch,
sk->sk_protocol, maddr);
break;
+ case ISDN_P_B_PCM:
case ISDN_P_B_RAW:
case ISDN_P_B_HDLC:
case ISDN_P_B_X75SLP:
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 4af8414..74d5734 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -5,6 +5,7 @@
* Basic declarations for the mISDN HW channels
*
* Copyright 2008 by Karsten Keil <kkeil@novell.com>
+ * Copyright 2009-2012 by Karsten Keil <kkeil@linux-pingi.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -148,6 +149,8 @@ struct bchannel {
u_int state;
void *hw;
int slot; /* multiport card channel slot */
+ int pcm_tx; /* PCM tx slot nr */
+ int pcm_rx; /* PCM rx slot nr */
struct timer_list timer;
/* receive data */
struct sk_buff *rx_skb;
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index b5e7f22..bdda647 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 21
+#define MISDN_RELEASE 24
/* primitives for information exchange
* generell format
@@ -229,7 +229,7 @@
#define ISDN_P_B_MASK 0x1f
#define ISDN_P_B_START 0x20
-
+#define ISDN_P_B_PCM 0x20
#define ISDN_P_B_RAW 0x21
#define ISDN_P_B_HDLC 0x22
#define ISDN_P_B_X75SLP 0x23
@@ -360,8 +360,8 @@ clear_channelmap(u_int nr, u_char *map)
#define MISDN_CTRL_LOOP 0x0001
#define MISDN_CTRL_CONNECT 0x0002
#define MISDN_CTRL_DISCONNECT 0x0004
-#define MISDN_CTRL_PCMCONNECT 0x0010
-#define MISDN_CTRL_PCMDISCONNECT 0x0020
+#define MISDN_CTRL_GET_PCM_SLOTS 0x0010
+#define MISDN_CTRL_SET_PCM_SLOTS 0x0020
#define MISDN_CTRL_SETPEER 0x0040
#define MISDN_CTRL_UNSETPEER 0x0080
#define MISDN_CTRL_RX_OFF 0x0100
@@ -381,6 +381,10 @@ clear_channelmap(u_int nr, u_char *map)
#define MISDN_CTRL_HFC_WD_INIT 0x4009
#define MISDN_CTRL_HFC_WD_RESET 0x400A
+/* special PCM slot numbers */
+#define MISDN_PCM_SLOT_DISABLE -1 /* PCM disabled */
+#define MISDN_PCM_SLOT_IGNORE -2 /* PCM setting will be not changed */
+
/* socket options */
#define MISDN_TIME_STAMP 0x0001
@@ -389,6 +393,7 @@ struct mISDN_ctrl_req {
int channel;
int p1;
int p2;
+ int p3;
};
/* muxer options */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 08/28] mISDN: Fix division by zero
From: Karsten Keil @ 2012-03-17 10:03 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
If DTMF debug is set and tresh goes under 100, the printk will cause
a division by zero.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/dsp_dtmf.c | 19 ++++++++++++++-----
1 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c
index 887860b..642f30b 100644
--- a/drivers/isdn/mISDN/dsp_dtmf.c
+++ b/drivers/isdn/mISDN/dsp_dtmf.c
@@ -222,16 +222,25 @@ coefficients:
goto storedigit;
}
- if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
+ if (dsp_debug & DEBUG_DSP_DTMFCOEFF) {
+ s32 tresh_100 = tresh/100;
+
+ if (tresh_100 == 0) {
+ tresh_100 = 1;
+ printk(KERN_DEBUG
+ "tresh(%d) too small set tresh/100 to 1\n",
+ tresh);
+ }
printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
" tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
result[0] / 10000, result[1] / 10000, result[2] / 10000,
result[3] / 10000, result[4] / 10000, result[5] / 10000,
result[6] / 10000, result[7] / 10000, tresh / 10000,
- result[0] / (tresh / 100), result[1] / (tresh / 100),
- result[2] / (tresh / 100), result[3] / (tresh / 100),
- result[4] / (tresh / 100), result[5] / (tresh / 100),
- result[6] / (tresh / 100), result[7] / (tresh / 100));
+ result[0] / (tresh_100), result[1] / (tresh_100),
+ result[2] / (tresh_100), result[3] / (tresh_100),
+ result[4] / (tresh_100), result[5] / (tresh_100),
+ result[6] / (tresh_100), result[7] / (tresh_100));
+ }
/* calc digit (lowgroup/highgroup) */
lowgroup = -1;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 11/28] mISDN: Add PCM only B-channel protocol to socket functions
From: Karsten Keil @ 2012-03-17 14:59 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/mISDN/socket.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 1254d8d..502bcf1 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -270,6 +270,7 @@ data_sock_release(struct socket *sock)
break;
case ISDN_P_LAPD_TE:
case ISDN_P_LAPD_NT:
+ case ISDN_P_B_PCM:
case ISDN_P_B_RAW:
case ISDN_P_B_HDLC:
case ISDN_P_B_X75SLP:
@@ -801,6 +802,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
case ISDN_P_NT_E1:
case ISDN_P_LAPD_TE:
case ISDN_P_LAPD_NT:
+ case ISDN_P_B_PCM:
case ISDN_P_B_RAW:
case ISDN_P_B_HDLC:
case ISDN_P_B_X75SLP:
--
1.7.3.4
^ permalink raw reply related
* [PATCH 06/28] mISDN: Rework of LED status display for HFC-4S/8S/E1 cards.
From: Karsten Keil @ 2012-03-17 9:55 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <jolly@eversberg.eu>
LEDs will show RED if layer 1 is disabled or fails.
LEDs will show GREEN if layer 1 is active.
LEDs will blink if traffic on D-channel.
Signed-off-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfc_multi.h | 9 +-
drivers/isdn/hardware/mISDN/hfcmulti.c | 157 ++++++++++++++++++-------------
2 files changed, 95 insertions(+), 71 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h
index b0588ac..09e4e77 100644
--- a/drivers/isdn/hardware/mISDN/hfc_multi.h
+++ b/drivers/isdn/hardware/mISDN/hfc_multi.h
@@ -205,18 +205,19 @@ struct hfc_multi {
u_int slots; /* number of PCM slots */
u_int leds; /* type of leds */
- u_int ledcount; /* used to animate leds */
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 activity_tx; /* if there is data TX / RX */
+ u_int activity_rx; /* bitmask according to port number */
+ /* (will be cleared after */
+ /* showing led-states) */
+ u_int flash[8]; /* counter for flashing 8 leds on activity */
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 */
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index cc978e8..876f7d0 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -1607,40 +1607,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
- * todo 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
*/
+ led[0] = 0;
+ led[1] = 0;
+ led[2] = 0;
+ led[3] = 0;
dch = hc->chan[hc->dslot].dch;
- if (test_bit(FLG_ACTIVE, &dch->Flags)) {
- led[0] = 0;
- led[1] = 0;
- led[2] = 0;
- led[3] = 1;
- } else {
- if (dch->dev.D.protocol
- != ISDN_P_NT_E1) {
- led[0] = 1;
+ if (dch) {
+ if (hc->chan[hc->dslot].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;
}
leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF;
/* leds are inverted */
@@ -1651,9 +1657,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 +1675,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 +1721,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 +1739,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 +1767,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 +1785,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 +1813,8 @@ hfcmulti_leds(struct hfc_multi *hc)
}
break;
}
+ hc->activity_tx = 0;
+ hc->activity_rx = 0;
}
/*
* read dtmf coefficients
@@ -2093,7 +2114,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;
@@ -2236,7 +2258,8 @@ next_frame:
}
}
/* 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)) {
--
1.7.3.4
^ permalink raw reply related
* [PATCH 03/28] mISDN: Fixed false interruption of audio during bridging change.
From: Karsten Keil @ 2012-03-17 9:34 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <jolly@eversberg.eu>
Transmitted audio data was interrupted if a bridge was enabled or disabled.
Now transmission seamlessly continues during that action.
Fix in hfcmulti.ko
Signed-off-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfcmulti.c | 24 ++++++++++++++++--------
1 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 0332231..c4e7fda 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3018,8 +3018,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 +3041,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 +3063,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 +3081,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] |=
--
1.7.3.4
^ permalink raw reply related
* [PATCH 05/28] mISDN: Using FLG_ACTIVE flag to determine if layer 1 is active or not.
From: Karsten Keil @ 2012-03-17 9:41 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
From: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfcmulti.c | 25 ++++++++++---------------
1 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index c4e7fda..cc978e8 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -1619,10 +1619,16 @@ hfcmulti_leds(struct hfc_multi *hc)
* 2 red steady: TE mode deactivate
* left green: L1 active
* left red: frame sync, but no L1
- * right green: L2 active
+ * todo right green: L2 active
*/
- if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */
- if (hc->chan[hc->dslot].dch->dev.D.protocol
+ dch = hc->chan[hc->dslot].dch;
+ if (test_bit(FLG_ACTIVE, &dch->Flags)) {
+ led[0] = 0;
+ led[1] = 0;
+ led[2] = 0;
+ led[3] = 1;
+ } else {
+ if (dch->dev.D.protocol
!= ISDN_P_NT_E1) {
led[0] = 1;
led[1] = 1;
@@ -1635,12 +1641,6 @@ hfcmulti_leds(struct hfc_multi *hc)
}
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 */
@@ -4062,14 +4062,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__);
--
1.7.3.4
^ permalink raw reply related
* [PATCH 16/28] mISDN: Help to identify L2 issues
From: Karsten Keil @ 2012-03-18 13:38 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
With multiple cards is hard to figure out which port cause trouble.
Now we have the informations in the log output.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/core.c | 16 +++++++++
drivers/isdn/mISDN/layer2.c | 75 ++++++++++++++++++++++++------------------
include/linux/mISDNif.h | 3 +-
3 files changed, 61 insertions(+), 33 deletions(-)
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index a24530f..c401634 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -355,6 +355,22 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp)
}
EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
+static const char *msg_no_channel = "<no channel>";
+static const char *msg_no_stack = "<no stack>";
+static const char *msg_no_stackdev = "<no stack device>";
+
+const char *mISDNDevName4ch(struct mISDNchannel *ch)
+{
+ if (!ch)
+ return msg_no_channel;
+ if (!ch->st)
+ return msg_no_stack;
+ if (!ch->st->dev)
+ return msg_no_stackdev;
+ return dev_name(&ch->st->dev->dev);
+};
+EXPORT_SYMBOL(mISDNDevName4ch);
+
static int
mISDNInit(void)
{
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index d421495..2829d93 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -110,8 +110,8 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...)
vaf.fmt = fmt;
vaf.va = &va;
- printk(KERN_DEBUG "l2 (sapi %d tei %d): %pV\n",
- l2->sapi, l2->tei, &vaf);
+ printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n",
+ mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf);
va_end(va);
}
@@ -154,7 +154,8 @@ l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb)
mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr;
err = l2->up->send(l2->up, skb);
if (err) {
- printk(KERN_WARNING "%s: err=%d\n", __func__, err);
+ printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
+ mISDNDevName4ch(&l2->ch), err);
dev_kfree_skb(skb);
}
}
@@ -178,7 +179,8 @@ l2up_create(struct layer2 *l2, u_int prim, int len, void *arg)
memcpy(skb_put(skb, len), arg, len);
err = l2->up->send(l2->up, skb);
if (err) {
- printk(KERN_WARNING "%s: err=%d\n", __func__, err);
+ printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
+ mISDNDevName4ch(&l2->ch), err);
dev_kfree_skb(skb);
}
}
@@ -189,7 +191,8 @@ l2down_skb(struct layer2 *l2, struct sk_buff *skb) {
ret = l2->ch.recv(l2->ch.peer, skb);
if (ret && (*debug & DEBUG_L2_RECV))
- printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret);
+ printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n",
+ mISDNDevName4ch(&l2->ch), ret);
return ret;
}
@@ -289,18 +292,18 @@ l2_timeout(struct FsmInst *fi, int event, void *arg)
skb = mI_alloc_skb(0, GFP_ATOMIC);
if (!skb) {
- printk(KERN_WARNING "L2(%d,%d) nr:%x timer %s lost - no skb\n",
- l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
- "T200" : "T203");
+ printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n",
+ mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
+ l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
return;
}
hh = mISDN_HEAD_P(skb);
hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
hh->id = l2->ch.nr;
if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "L2(%d,%d) nr:%x timer %s expired\n",
- l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
- "T200" : "T203");
+ printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n",
+ mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
+ l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
if (l2->ch.st)
l2->ch.st->own.recv(&l2->ch.st->own, skb);
}
@@ -309,8 +312,8 @@ static int
l2mgr(struct layer2 *l2, u_int prim, void *arg) {
long c = (long)arg;
- printk(KERN_WARNING
- "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c);
+ printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n",
+ mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c);
if (test_bit(FLG_LAPD, &l2->flag) &&
!test_bit(FLG_FIXED_TEI, &l2->flag)) {
switch (c) {
@@ -632,8 +635,8 @@ send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr)
else {
skb = mI_alloc_skb(i, GFP_ATOMIC);
if (!skb) {
- printk(KERN_WARNING "%s: can't alloc skbuff\n",
- __func__);
+ printk(KERN_WARNING "%s: can't alloc skbuff in %s\n",
+ mISDNDevName4ch(&l2->ch), __func__);
return;
}
}
@@ -1118,8 +1121,8 @@ enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
skb = mI_alloc_skb(i, GFP_ATOMIC);
if (!skb) {
- printk(KERN_WARNING
- "isdnl2 can't alloc sbbuff for enquiry_cr\n");
+ printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n",
+ mISDNDevName4ch(&l2->ch), __func__);
return;
}
memcpy(skb_put(skb, i), tmp, i);
@@ -1179,7 +1182,7 @@ invoke_retransmission(struct layer2 *l2, unsigned int nr)
else
printk(KERN_WARNING
"%s: windowar[%d] is NULL\n",
- __func__, p1);
+ mISDNDevName4ch(&l2->ch), p1);
l2->windowar[p1] = NULL;
}
mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
@@ -1490,8 +1493,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
p1 = (l2->vs - l2->va) % 8;
p1 = (p1 + l2->sow) % l2->window;
if (l2->windowar[p1]) {
- printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
- p1);
+ printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
+ mISDNDevName4ch(&l2->ch), p1);
dev_kfree_skb(l2->windowar[p1]);
}
l2->windowar[p1] = skb;
@@ -1511,12 +1514,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
memcpy(skb_push(nskb, i), header, i);
else {
printk(KERN_WARNING
- "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
+ "%s: L2 pull_iqueue skb header(%d/%d) too short\n",
+ mISDNDevName4ch(&l2->ch), i, p1);
oskb = nskb;
nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC);
if (!nskb) {
dev_kfree_skb(oskb);
- printk(KERN_WARNING "%s: no skb mem\n", __func__);
+ printk(KERN_WARNING "%s: no skb mem in %s\n",
+ mISDNDevName4ch(&l2->ch), __func__);
return;
}
memcpy(skb_put(nskb, i), header, i);
@@ -1892,7 +1897,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
ptei = *datap++;
if ((psapi & 1) || !(ptei & 1)) {
printk(KERN_WARNING
- "l2 D-channel frame wrong EA0/EA1\n");
+ "%s l2 D-channel frame wrong EA0/EA1\n",
+ mISDNDevName4ch(&l2->ch));
return ret;
}
psapi >>= 2;
@@ -1901,7 +1907,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
/* not our business */
if (*debug & DEBUG_L2)
printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
- __func__, psapi, l2->sapi);
+ mISDNDevName4ch(&l2->ch), psapi, l2->sapi);
dev_kfree_skb(skb);
return 0;
}
@@ -1909,7 +1915,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
/* not our business */
if (*debug & DEBUG_L2)
printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
- __func__, ptei, l2->tei);
+ mISDNDevName4ch(&l2->ch), ptei, l2->tei);
dev_kfree_skb(skb);
return 0;
}
@@ -1950,7 +1956,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
} else
c = 'L';
if (c) {
- printk(KERN_WARNING "l2 D-channel frame error %c\n", c);
+ printk(KERN_WARNING "%s:l2 D-channel frame error %c\n",
+ mISDNDevName4ch(&l2->ch), c);
mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
}
return ret;
@@ -1964,15 +1971,16 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
int ret = -EINVAL;
if (*debug & DEBUG_L2_RECV)
- printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n",
- __func__, hh->prim, hh->id, l2->sapi, l2->tei);
+ printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n",
+ __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id,
+ l2->sapi, l2->tei);
if (hh->prim == DL_INTERN_MSG) {
struct mISDNhead *chh = hh + 1; /* saved copy */
*hh = *chh;
if (*debug & DEBUG_L2_RECV)
printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
- __func__, hh->prim, hh->id);
+ mISDNDevName4ch(&l2->ch), hh->prim, hh->id);
}
switch (hh->prim) {
case PH_DATA_IND:
@@ -2053,7 +2061,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg)
int ret = -EINVAL;
if (*debug & DEBUG_L2_TEI)
- printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd);
+ printk(KERN_DEBUG "%s: cmd(%x) in %s\n",
+ mISDNDevName4ch(&l2->ch), cmd, __func__);
switch (cmd) {
case (MDL_ASSIGN_REQ):
ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg);
@@ -2066,7 +2075,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg)
break;
case (MDL_ERROR_RSP):
/* ETS 300-125 5.3.2.1 Test: TC13010 */
- printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n");
+ printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n",
+ mISDNDevName4ch(&l2->ch));
ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
break;
}
@@ -2098,7 +2108,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
u_int info;
if (*debug & DEBUG_L2_CTRL)
- printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
+ printk(KERN_DEBUG "%s: %s cmd(%x)\n",
+ mISDNDevName4ch(ch), __func__, cmd);
switch (cmd) {
case OPEN_CHANNEL:
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 322d316..f474f40 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 27
+#define MISDN_RELEASE 28
/* primitives for information exchange
* generell format
@@ -598,6 +598,7 @@ static inline struct mISDNdevice *dev_to_mISDN(struct device *dev)
extern void set_channel_address(struct mISDNchannel *, u_int, u_int);
extern void mISDN_clock_update(struct mISDNclock *, int, struct timeval *);
extern unsigned short mISDN_clock_get(void);
+extern const char *mISDNDevName4ch(struct mISDNchannel *);
#endif /* __KERNEL__ */
#endif /* mISDNIF_H */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 22/28] mISDN: More support for MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF
From: Karsten Keil @ 2012-04-21 15:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Add a common HW flag to support RX_OFF.
Implement MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF for the avmfritz
driver.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/hardware/mISDN/avmfritz.c | 169 ++++++++++++++++++++++++--------
drivers/isdn/mISDN/hwchannel.c | 1 +
include/linux/mISDNhw.h | 4 +-
include/linux/mISDNif.h | 10 ++-
4 files changed, 139 insertions(+), 45 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 9cee744..3781446 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -141,6 +141,8 @@ struct fritzcard {
struct isac_hw isac;
struct hdlc_hw hdlc[2];
struct bchannel bch[2];
+ int dropcnt[2];
+ u8 fill[2 * HDLC_FIFO_SIZE_V2];
char log[LOG_SIZE + 1];
};
@@ -402,35 +404,45 @@ static void
hdlc_empty_fifo(struct bchannel *bch, int count)
{
u32 *ptr;
- u8 *p;
+ u8 *p, copy;
u32 val, addr;
int cnt;
struct fritzcard *fc = bch->hw;
pr_debug("%s: %s %d\n", fc->name, __func__, count);
- if (!bch->rx_skb) {
- if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
- if (count >= bch->minlen)
- cnt = count;
- else
- cnt = 2 * bch->minlen;
- } else
- cnt = bch->maxlen;
- bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
+ if (test_bit(FLG_RX_OFF, &bch->Flags)) {
+ /* We drop the content, but need to read all bytes from FIFO */
+ copy = 0;
+ if (debug & DEBUG_HW_BFIFO)
+ printk(KERN_DEBUG "Dropped %d bytes - RX off\n", count);
+ val = (bch->nr - 1) & 1;
+ fc->dropcnt[val] += count;
+ } else {
+ copy = 1;
if (!bch->rx_skb) {
- pr_info("%s: B receive out of memory\n",
- fc->name);
+ if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+ if (count >= bch->minlen)
+ cnt = count;
+ else
+ cnt = 2 * bch->minlen;
+ } else
+ cnt = bch->maxlen;
+ bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
+ if (!bch->rx_skb) {
+ pr_info("%s: B receive out of memory\n",
+ fc->name);
+ return;
+ }
+ } else
+ cnt = skb_tailroom(bch->rx_skb);
+ if (count > cnt) {
+ pr_debug("%s: overrun %d + %d free %d\n", fc->name,
+ bch->rx_skb->len, count, cnt);
return;
}
- } else
- cnt = skb_tailroom(bch->rx_skb);
- if (count > cnt) {
- pr_debug("%s: overrun %d + %d free %d\n", fc->name,
- bch->rx_skb->len, count, cnt);
- return;
+ p = skb_put(bch->rx_skb, count);
+ ptr = (u32 *)p;
}
- p = skb_put(bch->rx_skb, count);
- ptr = (u32 *)p;
if (AVM_FRITZ_PCIV2 == fc->type)
addr = fc->addr + (bch->nr == 2 ?
AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
@@ -441,11 +453,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
cnt = 0;
while (cnt < count) {
val = le32_to_cpu(inl(addr));
- put_unaligned(val, ptr);
- ptr++;
+ if (copy) {
+ put_unaligned(val, ptr);
+ ptr++;
+ }
cnt += 4;
}
- if (debug & DEBUG_HW_BFIFO) {
+ if (copy && (debug & DEBUG_HW_BFIFO)) {
snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
bch->nr, fc->name, count);
print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
@@ -457,19 +471,25 @@ hdlc_fill_fifo(struct bchannel *bch)
{
struct fritzcard *fc = bch->hw;
struct hdlc_hw *hdlc;
- int count, fs, cnt = 0;
+ int count, fs, cnt = 0, idx;
u8 *p;
u32 *ptr, val, addr;
- hdlc = &fc->hdlc[(bch->nr - 1) & 1];
- if (!bch->tx_skb)
- return;
- count = bch->tx_skb->len - bch->tx_idx;
- if (count <= 0)
- return;
+ idx = (bch->nr - 1) & 1;
+ hdlc = &fc->hdlc[idx];
fs = (fc->type == AVM_FRITZ_PCIV2) ?
HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
- p = bch->tx_skb->data + bch->tx_idx;
+ if (!bch->tx_skb) {
+ if (!test_bit(FLG_FILLEMPTY, &bch->Flags))
+ return;
+ count = fs;
+ p = fc->fill + (idx * HDLC_FIFO_SIZE_V2);
+ } else {
+ count = bch->tx_skb->len - bch->tx_idx;
+ if (count <= 0)
+ return;
+ p = bch->tx_skb->data + bch->tx_idx;
+ }
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
if (count > fs) {
count = fs;
@@ -477,10 +497,13 @@ hdlc_fill_fifo(struct bchannel *bch)
if (test_bit(FLG_HDLC, &bch->Flags))
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
}
- pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
- bch->tx_idx, bch->tx_skb->len);
ptr = (u32 *)p;
- bch->tx_idx += count;
+ if (bch->tx_skb) {
+ pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
+ bch->tx_idx, bch->tx_skb->len);
+ bch->tx_idx += count;
+ } else
+ pr_debug("%s: %s fillempty %d\n", fc->name, __func__, count);
hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
if (AVM_FRITZ_PCIV2 == fc->type) {
__write_ctrl_pciv2(fc, hdlc, bch->nr);
@@ -509,11 +532,10 @@ HDLC_irq_xpr(struct bchannel *bch)
if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
hdlc_fill_fifo(bch);
else {
- if (bch->tx_skb) {
- /* send confirm, on trans, free on hdlc. */
+ if (bch->tx_skb)
dev_kfree_skb(bch->tx_skb);
- }
- if (get_next_bframe(bch))
+ if (get_next_bframe(bch) ||
+ test_bit(FLG_FILLEMPTY, &bch->Flags))
hdlc_fill_fifo(bch);
}
}
@@ -523,8 +545,9 @@ HDLC_irq(struct bchannel *bch, u32 stat)
{
struct fritzcard *fc = bch->hw;
int len, fs;
- u32 rmlMask;
+ u32 rmlMask, err;
struct hdlc_hw *hdlc;
+ struct sk_buff *skb;
hdlc = &fc->hdlc[(bch->nr - 1) & 1];
pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
@@ -546,6 +569,12 @@ HDLC_irq(struct bchannel *bch, u32 stat)
write_ctrl(bch, 1);
if (bch->rx_skb)
skb_trim(bch->rx_skb, 0);
+ if (test_bit(FLG_FIFO_STATUS, &bch->Flags)) {
+ skb = _alloc_mISDN_skb(PH_CONTROL_IND,
+ HW_FIFO_RDO, 0, NULL, GFP_KERNEL);
+ if (skb)
+ recv_Bchannel_skb(bch, skb);
+ }
} else {
len = (stat & rmlMask) >> 8;
if (!len)
@@ -575,13 +604,22 @@ handle_tx:
*/
pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
- if (bch->tx_skb)
+ if (bch->tx_skb) {
pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
fc->name, bch->nr, bch->tx_skb->len,
bch->tx_idx, bch->Flags);
- else
+ err = HW_FIFO_XDU_DATA;
+ } else {
pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",
fc->name, bch->nr, bch->Flags);
+ err = HW_FIFO_XDU_NODATA;
+ }
+ if (test_bit(FLG_FIFO_STATUS, &bch->Flags)) {
+ skb = _alloc_mISDN_skb(PH_CONTROL_IND, err,
+ 0, NULL, GFP_KERNEL);
+ if (skb)
+ recv_Bchannel_skb(bch, skb);
+ }
if (bch->tx_skb && bch->tx_skb->len) {
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
bch->tx_idx = 0;
@@ -721,6 +759,24 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
NULL, GFP_KERNEL);
ret = 0;
break;
+ case PH_CONTROL_REQ:
+ switch (hh->id) {
+ case HW_FIFO_STATUS_ON:
+ test_and_set_bit(FLG_FIFO_STATUS, &bch->Flags);
+ id = 0;
+ break;
+ case HW_FIFO_STATUS_OFF:
+ test_and_clear_bit(FLG_FIFO_STATUS, &bch->Flags);
+ id = 0;
+ break;
+ default:
+ pr_info("PH_CONTROL_REQ %x not supported\n", hh->id);
+ id = -EINVAL;
+ break;
+ }
+ _queue_data(ch, PH_CONTROL_CNF, id, 0, NULL, GFP_KERNEL);
+ ret = 0;
+ break;
}
if (!ret)
dev_kfree_skb(skb);
@@ -835,12 +891,39 @@ init_card(struct fritzcard *fc)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
- int ret = 0, o1, o2;
+ int ret = 0, o1, o2, idx;
+ u8 *p;
struct fritzcard *fc = bch->hw;
+ idx = (bch->nr - 1) & 1;
switch (cq->op) {
case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_RX_BUFFER;
+ cq->op = MISDN_CTRL_RX_BUFFER |
+ MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
+ break;
+ case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
+ o1 = fc->dropcnt[idx];
+ if (cq->p1) {
+ test_and_set_bit(FLG_RX_OFF, &bch->Flags);
+ fc->dropcnt[idx] = 0;
+ } else
+ test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
+ cq->p2 = o1;
+ if (debug & DEBUG_HW_BCHANNEL)
+ printk(KERN_DEBUG "Bch%d RX %s\n",
+ bch->nr, cq->p1 ? "off" : "on");
+ break;
+ case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+ p = fc->fill + (idx * HDLC_FIFO_SIZE_V2);
+ if (cq->p1) {
+ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (cq->p2 > -1)
+ memset(p, cq->p2 & 0xff, HDLC_FIFO_SIZE_V2);
+ } else
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (debug & DEBUG_HW_BCHANNEL)
+ printk(KERN_DEBUG "FILL_EMPTY Bch%d %s val %02x\n",
+ bch->nr, cq->p1 ? "on" : "off", *p);
break;
case MISDN_CTRL_RX_BUFFER:
/* We return the old values */
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 467518c..84fbcf1 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -135,6 +135,7 @@ mISDN_clear_bchannel(struct bchannel *ch)
test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
+ test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
}
EXPORT_SYMBOL(mISDN_clear_bchannel);
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 4f97bd3..9776edd 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -73,7 +73,9 @@
#define FLG_LL_OK 24
#define FLG_LL_CONN 25
#define FLG_DTMFSEND 26
-
+/* stop sending received data upstream */
+#define FLG_RX_OFF 27
+#define FLG_FIFO_STATUS 28
/* workq events */
#define FLG_RECVQUEUE 30
#define FLG_PHCHANGE 31
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index b26de1a..89ce4ec 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 30
+#define MISDN_RELEASE 31
/* primitives for information exchange
* generell format
@@ -158,6 +158,7 @@
#define HFC_VOL_CHANGE_RX 0x2602
#define HFC_SPL_LOOP_ON 0x2603
#define HFC_SPL_LOOP_OFF 0x2604
+
/* for T30 FAX and analog modem */
#define HW_MOD_FRM 0x4000
#define HW_MOD_FRH 0x4001
@@ -171,6 +172,13 @@
#define HW_MOD_READY 0x4014
#define HW_MOD_LASTDATA 0x4015
+/* Debug and status via PH_CONTROL */
+#define HW_FIFO_STATUS_OFF 0x8000
+#define HW_FIFO_STATUS_ON 0x8001
+#define HW_FIFO_RDO 0x8002
+#define HW_FIFO_XDU_DATA 0x8003
+#define HW_FIFO_XDU_NODATA 0x8004
+
/* DSP_TONE_PATT_ON parameter */
#define TONE_OFF 0x0000
#define TONE_GERMAN_DIALTONE 0x0001
--
1.7.3.4
^ permalink raw reply related
* [PATCH 21/28] mISDN: Add interface to allow upper layers to modify RX buffer limits
From: Karsten Keil @ 2012-04-21 15:26 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
It seems to be useful to let applications decide the
size of the data chunks they want receive.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/hardware/mISDN/avmfritz.c | 17 +++++++++++++----
drivers/isdn/hardware/mISDN/mISDNipac.c | 17 +++++++++++++----
include/linux/mISDNif.h | 11 ++++++++++-
3 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 4b1c86e..9cee744 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -835,15 +835,24 @@ init_card(struct fritzcard *fc)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
- int ret = 0;
+ int ret = 0, o1, o2;
struct fritzcard *fc = bch->hw;
switch (cq->op) {
case MISDN_CTRL_GETOP:
- cq->op = 0;
+ cq->op = MISDN_CTRL_RX_BUFFER;
+ break;
+ case MISDN_CTRL_RX_BUFFER:
+ /* We return the old values */
+ o1 = bch->minlen;
+ o2 = bch->maxlen;
+ if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p1;
+ if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p2;
+ cq->p1 = o1;
+ cq->p2 = o2;
break;
- /* Nothing implemented yet */
- case MISDN_CTRL_FILL_EMPTY:
default:
pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
ret = -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 1bc75ae..b32f5bb 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1395,14 +1395,23 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
- int ret = 0;
+ int ret = 0, o1, o2;
switch (cq->op) {
case MISDN_CTRL_GETOP:
- cq->op = 0;
+ cq->op = MISDN_CTRL_RX_BUFFER;
+ break;
+ case MISDN_CTRL_RX_BUFFER:
+ /* We return the old values */
+ o1 = bch->minlen;
+ o2 = bch->maxlen;
+ if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p1;
+ if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p2;
+ cq->p1 = o1;
+ cq->p2 = o2;
break;
- /* Nothing implemented yet */
- case MISDN_CTRL_FILL_EMPTY:
default:
pr_info("%s: unknown Op %x\n", __func__, cq->op);
ret = -EINVAL;
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 850fe1f..b26de1a 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 29
+#define MISDN_RELEASE 30
/* primitives for information exchange
* generell format
@@ -367,6 +367,7 @@ clear_channelmap(u_int nr, u_char *map)
#define MISDN_CTRL_LOOP 0x00000001
#define MISDN_CTRL_CONNECT 0x00000002
#define MISDN_CTRL_DISCONNECT 0x00000004
+#define MISDN_CTRL_RX_BUFFER 0x00000008
#define MISDN_CTRL_GET_PCM_SLOTS 0x00000010
#define MISDN_CTRL_SET_PCM_SLOTS 0x00000020
#define MISDN_CTRL_SETPEER 0x00000040
@@ -394,6 +395,14 @@ clear_channelmap(u_int nr, u_char *map)
#define MISDN_CTRL_L1_TS0_MODE 0x00010003
#define MISDN_CTRL_L1_GET_SYNC_INFO 0x00010004
+/* special RX buffer values for MISDN_CTRL_RX_BUFFER
+ * req.p1 is minimum buffer size, req.p2 the maximum
+ * MISDN_CTRL_RX_SIZE_ IGNORE value will not change but is still read back
+ */
+#define MISDN_CTRL_RX_SIZE_NOCHECK -1
+#define MISDN_CTRL_RX_SIZE_IGNORE -2
+
+
/* special PCM slot numbers */
#define MISDN_PCM_SLOT_DISABLE -1 /* PCM disabled */
#define MISDN_PCM_SLOT_IGNORE -2 /* PCM setting will be not changed */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 27/28] mISDN: Add X-Tensions USB ISDN TA XC-525
From: Karsten Keil @ 2012-04-21 16:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
>From http://www.ip-phone-forum.de/showthread.php?t=225313
Thanks to Lars Immisch for pointing to this.
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfcsusb.h | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
index 7d48b86..56e9755 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.h
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -341,6 +341,12 @@ static const char *HFC_NT_LAYER1_STATES[HFC_MAX_NT_LAYER1_STATE + 1] = {
/* supported devices */
static struct usb_device_id hfcsusb_idtab[] = {
{
+ USB_DEVICE(0x1ae7, 0x0525),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x88, -64, -32, -16},
+ "X-Tensions USB ISDN TA XC-525"}),
+ },
+ {
USB_DEVICE(0x0959, 0x2bd0),
.driver_info = (unsigned long) &((struct hfcsusb_vdata)
{LED_OFF, {4, 0, 2, 1},
--
1.7.3.4
^ permalink raw reply related
* [PATCH 00/28] MISDN patchset for net-next
From: Karsten Keil @ 2012-04-23 16:03 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Hello David,
please include thes patches into netnext.
This patch collection contains bugfixes and enhancemets to make
the mISDN stack ready for Fax G3 support in CAPI20 (in userspace).
Tested against net-next from today.
Andreas Eversberg (7):
mISDN: Fix NULL pointer bug in if-condition of mISDN_dsp
mISDN: Fixed hardware bridging/conference check routine of
mISDN_dsp.ko.
mISDN: Fixed false interruption of audio during bridging change.
mISDN: Added PH_* state info to tei manager.
mISDN: Using FLG_ACTIVE flag to determine if layer 1 is active or
not.
mISDN: Rework of LED status display for HFC-4S/8S/E1 cards.
mISDN: Added support for fragmentation of E1 interfaces of hfcmulti
driver.
Karsten Keil (20):
mISDN: Fix division by zero
mISDN: Fix refcounting bug
mISDN: Add interface for PCM only access
mISDN: Add PCM only B-channel protocol to socket functions
mISDN: L2 timeouts need to be queued as L2 event
mISDN: Make layer1 timer 3 value configurable
mISDN: Layer1 statemachine fix
mISDN: DSP scheduling fix
mISDN: Help to identify L2 issues
mISDN: Add 2MBit mode for HFC E1 card
mISDN: Cleanup channel also if it already was deactivated
mISDN: Early confirm for transparent data
mISDN: Allow the driver to set a minimum length for transparent data
mISDN: Add interface to allow upper layers to modify RX buffer limits
mISDN: More support for MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF
mISDN: Fix compiler warnings
mISDN: Bufferlimits for hfcmulti
mISDN: Enhance hfcsusb driver
mISDN: Add X-Tensions USB ISDN TA XC-525
mISDN: Remove additonal PH_DATA confirm for raw data
Martin Bachem (1):
mISDN: Bugfix hfcsusb: usb endpoint activation/deactivation
drivers/isdn/hardware/mISDN/avmfritz.c | 254 ++++++--
drivers/isdn/hardware/mISDN/hfc_multi.h | 94 ++--
drivers/isdn/hardware/mISDN/hfcmulti.c | 1059 +++++++++++++++++++++----------
drivers/isdn/hardware/mISDN/hfcpci.c | 12 +-
drivers/isdn/hardware/mISDN/hfcsusb.c | 224 ++++---
drivers/isdn/hardware/mISDN/hfcsusb.h | 16 +-
drivers/isdn/hardware/mISDN/mISDNipac.c | 62 ++-
drivers/isdn/hardware/mISDN/mISDNisar.c | 22 +-
drivers/isdn/hardware/mISDN/netjet.c | 21 +-
drivers/isdn/hardware/mISDN/w6692.c | 22 +-
drivers/isdn/mISDN/core.c | 16 +
drivers/isdn/mISDN/dsp.h | 4 +-
drivers/isdn/mISDN/dsp_cmx.c | 19 +-
drivers/isdn/mISDN/dsp_dtmf.c | 19 +-
drivers/isdn/mISDN/hwchannel.c | 9 +-
drivers/isdn/mISDN/l1oip_core.c | 2 +-
drivers/isdn/mISDN/layer1.c | 37 +-
drivers/isdn/mISDN/layer2.c | 119 +++-
drivers/isdn/mISDN/socket.c | 3 +
drivers/isdn/mISDN/tei.c | 71 ++-
include/linux/mISDNhw.h | 13 +-
include/linux/mISDNif.h | 88 ++-
22 files changed, 1485 insertions(+), 701 deletions(-)
--
1.7.3.4
^ permalink raw reply
* [PATCH 13/28] mISDN: Make layer1 timer 3 value configurable
From: Karsten Keil @ 2012-03-17 15:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
For certification test it is useful to change the layer1
timer3 value on runtime.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/layer1.c | 16 ++++++++++++++--
include/linux/mISDNhw.h | 3 +++
include/linux/mISDNif.h | 3 ++-
3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c
index 0fc49b3..65912bd 100644
--- a/drivers/isdn/mISDN/layer1.c
+++ b/drivers/isdn/mISDN/layer1.c
@@ -30,11 +30,12 @@ struct layer1 {
struct FsmInst l1m;
struct FsmTimer timer;
int delay;
+ int t3_value;
struct dchannel *dch;
dchannel_l1callback *dcb;
};
-#define TIMER3_VALUE 7000
+#define TIMER3_DEFAULT_VALUE 7000
static
struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL};
@@ -233,7 +234,7 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg)
{
struct layer1 *l1 = fi->userdata;
- mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+ mISDN_FsmRestartTimer(&l1->timer, l1->t3_value, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
l1->dcb(l1->dch, HW_RESET_REQ);
}
@@ -356,6 +357,16 @@ l1_event(struct layer1 *l1, u_int event)
release_l1(l1);
break;
default:
+ if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) {
+ int val = event & HW_TIMER3_VMASK;
+
+ if (val < 5)
+ val = 5;
+ if (val > 30)
+ val = 30;
+ l1->t3_value = val;
+ break;
+ }
if (*debug & DEBUG_L1)
printk(KERN_DEBUG "%s %x unhandled\n",
__func__, event);
@@ -377,6 +388,7 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) {
nl1->l1m.fsm = &l1fsm_s;
nl1->l1m.state = ST_L1_F3;
nl1->Flags = 0;
+ nl1->t3_value = TIMER3_DEFAULT_VALUE;
nl1->l1m.debug = *debug & DEBUG_L1_FSM;
nl1->l1m.userdata = nl1;
nl1->l1m.userint = 0;
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 74d5734..7075753 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -136,6 +136,9 @@ extern int create_l1(struct dchannel *, dchannel_l1callback *);
#define HW_TESTRX_RAW 0x9602
#define HW_TESTRX_HDLC 0x9702
#define HW_TESTRX_OFF 0x9802
+#define HW_TIMER3_IND 0x9902
+#define HW_TIMER3_VALUE 0x9a00
+#define HW_TIMER3_VMASK 0x00FF
struct layer1;
extern int l1_event(struct layer1 *, u_int);
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index b7457e8..322d316 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 26
+#define MISDN_RELEASE 27
/* primitives for information exchange
* generell format
@@ -374,6 +374,7 @@ clear_channelmap(u_int nr, u_char *map)
#define MISDN_CTRL_RX_OFF 0x0100
#define MISDN_CTRL_FILL_EMPTY 0x0200
#define MISDN_CTRL_GETPEER 0x0400
+#define MISDN_CTRL_L1_TIMER3 0x0800
#define MISDN_CTRL_HW_FEATURES_OP 0x2000
#define MISDN_CTRL_HW_FEATURES 0x2001
#define MISDN_CTRL_HFC_OP 0x4000
--
1.7.3.4
^ permalink raw reply related
* [PATCH 28/28] mISDN: Remove additonal PH_DATA confirm for raw data
From: Karsten Keil @ 2012-04-21 16:27 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Now the confirm is already done in get_next_bframe to
allow early delivery of the next data from higher layers.
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfcmulti.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 50d10ea..7662148 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2180,10 +2180,6 @@ 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 */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 15/28] mISDN: DSP scheduling fix
From: Karsten Keil @ 2012-03-18 13:34 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
dsp_spl_jiffies need to be the same datatype as jiffies (which is ulong).
If not, on 64 bit systems it will fallback to schedule the DSP every jiffie
tic as soon jiffies become > 2^32.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/mISDN/dsp.h | 4 +++-
drivers/isdn/mISDN/dsp_cmx.c | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h
index afe4173..e020957 100644
--- a/drivers/isdn/mISDN/dsp.h
+++ b/drivers/isdn/mISDN/dsp.h
@@ -76,7 +76,9 @@ extern u8 dsp_silence;
#define MAX_SECONDS_JITTER_CHECK 5
extern struct timer_list dsp_spl_tl;
-extern u32 dsp_spl_jiffies;
+
+/* the datatype need to match jiffies datatype */
+extern ulong dsp_spl_jiffies;
/* the structure of conferences:
*
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index 0c104b9..3a3b3a5 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -1624,7 +1624,7 @@ send_packet:
static u32 jittercount; /* counter for jitter check */
struct timer_list dsp_spl_tl;
-u32 dsp_spl_jiffies; /* calculate the next time to fire */
+ulong dsp_spl_jiffies; /* calculate the next time to fire */
static u16 dsp_count; /* last sample count */
static int dsp_count_valid; /* if we have last sample count */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 24/28] mISDN: Bufferlimits for hfcmulti
From: Karsten Keil @ 2012-04-21 15:55 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Implement the minimum packet length for transparent data.
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/hfcmulti.c | 51 +++++++++++++++++++++++---------
1 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 144c35a..50d10ea 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2374,25 +2374,36 @@ next_frame:
} else {
/* transparent */
if (*sp == NULL) {
- *sp = mI_alloc_skb(Zsize, GFP_ATOMIC);
+ if (Zsize >= bch->minlen)
+ temp = Zsize;
+ else
+ temp = 2 * bch->minlen;
+ if (temp > maxlen)
+ temp = maxlen;
+
+ *sp = mI_alloc_skb(temp, GFP_ATOMIC);
if (*sp == NULL) {
printk(KERN_DEBUG "%s: No mem for rx_skb\n",
__func__);
return;
}
}
- if (Zsize > skb_tailroom(*sp))
- Zsize = skb_tailroom(*sp);
- hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
- skb = NULL;
+ temp = Zsize;
+ if (temp > skb_tailroom(*sp))
+ temp = skb_tailroom(*sp);
+ hc->read_fifo(hc, skb_put(*sp, temp), temp);
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;
+ "%s(card %d): fifo(%d) reading %d/%d bytes "
+ "(z1=%04x, z2=%04x) TRANS\n", __func__,
+ hc->id + 1, ch, temp, Zsize, z1, z2);
+ Zsize -= temp;
+ if ((*sp)->len >= bch->minlen) {
+ recv_Bchannel(bch, hc->chan[ch].Zfill);
+ *sp = NULL;
+ if (Zsize)
+ goto next_frame;
+ }
}
}
@@ -3678,21 +3689,21 @@ static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
int ret = 0;
- struct dsp_features *features =
- (struct dsp_features *)(*((u_long *)&cq->p1));
+ struct dsp_features *features;
struct hfc_multi *hc = bch->hw;
int slot_tx;
int bank_tx;
int slot_rx;
int bank_rx;
int num;
+ int o1, o2;
u8 v1, v2;
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 |
- MISDN_CTRL_L1_TESTS;
+ MISDN_CTRL_L1_TESTS | MISDN_CTRL_RX_BUFFER;
break;
case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
hc->chan[bch->slot].rx_off = !!cq->p1;
@@ -3714,6 +3725,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
"off=%d)\n", __func__, bch->nr, !!cq->p1);
break;
case MISDN_CTRL_HW_FEATURES: /* fill features structure */
+ features = (struct dsp_features *)(*((u_long *)&cq->p1));
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HW_FEATURE request\n",
__func__);
@@ -3831,6 +3843,17 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
cq->p3 = HFC_inb(hc, R_JATT_STA);
cq->p3 |= (HFC_inb(hc, R_SLIP) << 8);
break;
+ case MISDN_CTRL_RX_BUFFER:
+ /* We return the old values */
+ o1 = bch->minlen;
+ o2 = bch->maxlen;
+ if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p1;
+ if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p2;
+ cq->p1 = o1;
+ cq->p2 = o2;
+ break;
default:
printk(KERN_WARNING "%s: unknown Op %x\n",
__func__, cq->op);
--
1.7.3.4
^ permalink raw reply related
* [PATCH 20/28] mISDN: Allow the driver to set a minimum length for transparent data
From: Karsten Keil @ 2012-04-21 15:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
This is usefull for better flow control and will
avoid very short messages to upper layer.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/hardware/mISDN/avmfritz.c | 88 +++++++++++++++++++++----------
drivers/isdn/hardware/mISDN/hfcmulti.c | 4 +-
drivers/isdn/hardware/mISDN/hfcpci.c | 2 +-
drivers/isdn/hardware/mISDN/hfcsusb.c | 2 +-
drivers/isdn/hardware/mISDN/mISDNipac.c | 25 ++++++---
drivers/isdn/hardware/mISDN/mISDNisar.c | 2 +-
drivers/isdn/hardware/mISDN/netjet.c | 2 +-
drivers/isdn/hardware/mISDN/w6692.c | 2 +-
drivers/isdn/mISDN/hwchannel.c | 3 +-
drivers/isdn/mISDN/l1oip_core.c | 2 +-
include/linux/mISDNhw.h | 3 +-
11 files changed, 90 insertions(+), 45 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index c773a7f..4b1c86e 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -30,7 +30,7 @@
#include "ipac.h"
-#define AVMFRITZ_REV "2.1"
+#define AVMFRITZ_REV "2.2"
static int AVM_cnt;
static int debug;
@@ -69,7 +69,8 @@ enum {
#define HDLC_MODE_TRANS 0x02
#define HDLC_MODE_CCR_7 0x04
#define HDLC_MODE_CCR_16 0x08
-#define HDLC_MODE_TESTLOOP 0x80
+#define HDLC_FIFO_SIZE_128 0x20
+#define HDLC_MODE_TESTLOOP_V1 0x80
#define HDLC_INT_XPR 0x80
#define HDLC_INT_XDU 0x40
@@ -80,13 +81,16 @@ enum {
#define HDLC_STAT_RDO 0x10
#define HDLC_STAT_CRCVFRRAB 0x0E
#define HDLC_STAT_CRCVFR 0x06
-#define HDLC_STAT_RML_MASK 0x3f00
+#define HDLC_STAT_RML_MASK_V1 0x3f00
+#define HDLC_STAT_RML_MASK_V2 0x7f00
#define HDLC_CMD_XRS 0x80
#define HDLC_CMD_XME 0x01
#define HDLC_CMD_RRS 0x20
#define HDLC_CMD_XML_MASK 0x3f00
-#define HDLC_FIFO_SIZE 32
+
+#define HDLC_FIFO_SIZE_V1 32
+#define HDLC_FIFO_SIZE_V2 128
/* Fritz PCI v2.0 */
@@ -346,11 +350,14 @@ modehdlc(struct bchannel *bch, int protocol)
{
struct fritzcard *fc = bch->hw;
struct hdlc_hw *hdlc;
+ u8 mode;
hdlc = &fc->hdlc[(bch->nr - 1) & 1];
pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,
'@' + bch->nr, bch->state, protocol, bch->nr);
hdlc->ctrl.ctrl = 0;
+ mode = (AVM_FRITZ_PCIV2 == fc->type) ? HDLC_FIFO_SIZE_128 : 0;
+
switch (protocol) {
case -1: /* used for init */
bch->state = -1;
@@ -358,7 +365,7 @@ modehdlc(struct bchannel *bch, int protocol)
if (bch->state == ISDN_P_NONE)
break;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+ hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
write_ctrl(bch, 5);
bch->state = ISDN_P_NONE;
test_and_clear_bit(FLG_HDLC, &bch->Flags);
@@ -367,7 +374,7 @@ modehdlc(struct bchannel *bch, int protocol)
case ISDN_P_B_RAW:
bch->state = protocol;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+ hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
write_ctrl(bch, 5);
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bch, 1);
@@ -377,7 +384,7 @@ modehdlc(struct bchannel *bch, int protocol)
case ISDN_P_B_HDLC:
bch->state = protocol;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+ hdlc->ctrl.sr.mode = mode | HDLC_MODE_ITF_FLG;
write_ctrl(bch, 5);
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bch, 1);
@@ -397,21 +404,29 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
u32 *ptr;
u8 *p;
u32 val, addr;
- int cnt = 0;
+ int cnt;
struct fritzcard *fc = bch->hw;
pr_debug("%s: %s %d\n", fc->name, __func__, count);
if (!bch->rx_skb) {
- bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);
+ if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+ if (count >= bch->minlen)
+ cnt = count;
+ else
+ cnt = 2 * bch->minlen;
+ } else
+ cnt = bch->maxlen;
+ bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
if (!bch->rx_skb) {
pr_info("%s: B receive out of memory\n",
fc->name);
return;
}
- }
- if ((bch->rx_skb->len + count) > bch->maxlen) {
- pr_debug("%s: overrun %d\n", fc->name,
- bch->rx_skb->len + count);
+ } else
+ cnt = skb_tailroom(bch->rx_skb);
+ if (count > cnt) {
+ pr_debug("%s: overrun %d + %d free %d\n", fc->name,
+ bch->rx_skb->len, count, cnt);
return;
}
p = skb_put(bch->rx_skb, count);
@@ -423,6 +438,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
addr = fc->addr + CHIP_WINDOW;
outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
}
+ cnt = 0;
while (cnt < count) {
val = le32_to_cpu(inl(addr));
put_unaligned(val, ptr);
@@ -441,7 +457,7 @@ hdlc_fill_fifo(struct bchannel *bch)
{
struct fritzcard *fc = bch->hw;
struct hdlc_hw *hdlc;
- int count, cnt = 0;
+ int count, fs, cnt = 0;
u8 *p;
u32 *ptr, val, addr;
@@ -451,10 +467,12 @@ hdlc_fill_fifo(struct bchannel *bch)
count = bch->tx_skb->len - bch->tx_idx;
if (count <= 0)
return;
+ fs = (fc->type == AVM_FRITZ_PCIV2) ?
+ HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
p = bch->tx_skb->data + bch->tx_idx;
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
- if (count > HDLC_FIFO_SIZE) {
- count = HDLC_FIFO_SIZE;
+ if (count > fs) {
+ count = fs;
} else {
if (test_bit(FLG_HDLC, &bch->Flags))
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
@@ -463,7 +481,7 @@ hdlc_fill_fifo(struct bchannel *bch)
bch->tx_idx, bch->tx_skb->len);
ptr = (u32 *)p;
bch->tx_idx += count;
- hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
+ hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
if (AVM_FRITZ_PCIV2 == fc->type) {
__write_ctrl_pciv2(fc, hdlc, bch->nr);
addr = fc->addr + (bch->nr == 2 ?
@@ -493,8 +511,6 @@ HDLC_irq_xpr(struct bchannel *bch)
else {
if (bch->tx_skb) {
/* send confirm, on trans, free on hdlc. */
- if (test_bit(FLG_TRANSPARENT, &bch->Flags))
- confirm_Bsend(bch);
dev_kfree_skb(bch->tx_skb);
}
if (get_next_bframe(bch))
@@ -506,13 +522,23 @@ static void
HDLC_irq(struct bchannel *bch, u32 stat)
{
struct fritzcard *fc = bch->hw;
- int len;
+ int len, fs;
+ u32 rmlMask;
struct hdlc_hw *hdlc;
hdlc = &fc->hdlc[(bch->nr - 1) & 1];
pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
+ if (fc->type == AVM_FRITZ_PCIV2) {
+ rmlMask = HDLC_STAT_RML_MASK_V2;
+ fs = HDLC_FIFO_SIZE_V2;
+ } else {
+ rmlMask = HDLC_STAT_RML_MASK_V1;
+ fs = HDLC_FIFO_SIZE_V1;
+ }
if (stat & HDLC_INT_RPR) {
if (stat & HDLC_STAT_RDO) {
+ pr_warning("%s: ch%d stat %x RDO\n",
+ fc->name, bch->nr, stat);
hdlc->ctrl.sr.xml = 0;
hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
write_ctrl(bch, 1);
@@ -521,20 +547,20 @@ HDLC_irq(struct bchannel *bch, u32 stat)
if (bch->rx_skb)
skb_trim(bch->rx_skb, 0);
} else {
- len = (stat & HDLC_STAT_RML_MASK) >> 8;
+ len = (stat & rmlMask) >> 8;
if (!len)
- len = 32;
+ len = fs;
hdlc_empty_fifo(bch, len);
if (!bch->rx_skb)
goto handle_tx;
- if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT,
- &bch->Flags)) {
+ if ((stat & HDLC_STAT_RME) || (test_bit(FLG_TRANSPARENT,
+ &bch->Flags) && bch->rx_skb->len >= bch->minlen)) {
if (((stat & HDLC_STAT_CRCVFRRAB) ==
HDLC_STAT_CRCVFR) ||
test_bit(FLG_TRANSPARENT, &bch->Flags)) {
recv_Bchannel(bch, 0);
} else {
- pr_debug("%s: got invalid frame\n",
+ pr_warning("%s: got invalid frame\n",
fc->name);
skb_trim(bch->rx_skb, 0);
}
@@ -547,6 +573,8 @@ handle_tx:
* restart transmitting the whole frame on HDLC
* in transparent mode we send the next data
*/
+ pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
+ stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
if (bch->tx_skb)
pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
fc->name, bch->nr, bch->tx_skb->len,
@@ -643,7 +671,7 @@ avm_fritzv2_interrupt(int intno, void *dev_id)
mISDNisac_irq(&fc->isac, val);
}
if (sval & AVM_STATUS0_IRQ_TIMER) {
- pr_debug("%s: timer irq\n", fc->name);
+ pr_debug("%s: sval(%x) - timer irq\n", fc->name, sval);
outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
udelay(1);
outb(fc->ctrlreg, fc->addr + 2);
@@ -1013,7 +1041,7 @@ release_card(struct fritzcard *card)
static int __devinit
setup_instance(struct fritzcard *card)
{
- int i, err;
+ int i, err, minsize;
u_long flags;
snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1);
@@ -1033,7 +1061,11 @@ setup_instance(struct fritzcard *card)
for (i = 0; i < 2; i++) {
card->bch[i].nr = i + 1;
set_channelmap(i + 1, card->isac.dch.dev.channelmap);
- mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);
+ if (AVM_FRITZ_PCIV2 == card->type)
+ minsize = HDLC_FIFO_SIZE_V2;
+ else
+ minsize = HDLC_FIFO_SIZE_V1;
+ mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, minsize);
card->bch[i].hw = card;
card->bch[i].ch.send = avm_l2l1B;
card->bch[i].ch.ctrl = avm_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index d826586..884c090 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -5175,7 +5175,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
bch->nr = ch;
bch->slot = ch;
bch->debug = debug;
- mISDN_initbchannel(bch, MAX_DATA_MEM);
+ mISDN_initbchannel(bch, MAX_DATA_MEM, -1);
bch->hw = hc;
bch->ch.send = handle_bmsg;
bch->ch.ctrl = hfcm_bctrl;
@@ -5248,7 +5248,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, -1);
bch->hw = hc;
bch->ch.send = handle_bmsg;
bch->ch.ctrl = hfcm_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 6a0d964..76bb800 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -2117,7 +2117,7 @@ setup_card(struct hfc_pci *card)
card->bch[i].nr = i + 1;
set_channelmap(i + 1, card->dch.dev.channelmap);
card->bch[i].debug = debug;
- mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);
+ mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, -1);
card->bch[i].hw = card;
card->bch[i].ch.send = hfcpci_l2l1B;
card->bch[i].ch.ctrl = hfc_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 404184a..3c20b4f 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1876,7 +1876,7 @@ setup_instance(struct hfcsusb *hw, struct device *parent)
hw->bch[i].nr = i + 1;
set_channelmap(i + 1, hw->dch.dev.channelmap);
hw->bch[i].debug = debug;
- mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM);
+ mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, -1);
hw->bch[i].hw = hw;
hw->bch[i].ch.send = hfcusb_l2l1B;
hw->bch[i].ch.ctrl = hfc_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index d301d8c..1bc75ae 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -929,20 +929,29 @@ static void
hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
{
u8 *p;
+ int len;
pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
if (!hscx->bch.rx_skb) {
- hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
+ if (test_bit(FLG_TRANSPARENT, &hscx->bch.Flags)) {
+ if (count >= hscx->bch.minlen)
+ len = count;
+ else
+ len = 2 * hscx->bch.minlen;
+ } else
+ len = hscx->bch.maxlen;
+ hscx->bch.rx_skb = mI_alloc_skb(len, GFP_ATOMIC);
if (!hscx->bch.rx_skb) {
pr_info("%s: B receive out of memory\n",
hscx->ip->name);
hscx_cmdr(hscx, 0x80); /* RMC */
return;
}
- }
- if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) {
- pr_debug("%s: overrun %d\n", hscx->ip->name,
- hscx->bch.rx_skb->len + count);
+ } else
+ len = skb_tailroom(hscx->bch.rx_skb);
+ if (count > len) {
+ pr_debug("%s: overrun %d + %d free %d\n", hscx->ip->name,
+ hscx->bch.rx_skb->len, count, len);
skb_trim(hscx->bch.rx_skb, 0);
hscx_cmdr(hscx, 0x80); /* RMC */
return;
@@ -1122,7 +1131,8 @@ ipac_irq(struct hscx_hw *hx, u8 ista)
hscx_empty_fifo(hx, hx->fifo_size);
if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
/* receive transparent audio data */
- if (hx->bch.rx_skb)
+ if (hx->bch.rx_skb &&
+ (hx->bch.rx_skb->len >= hx->bch.minlen))
recv_Bchannel(&hx->bch, 0);
}
}
@@ -1613,7 +1623,8 @@ mISDNipac_init(struct ipac_hw *ipac, void *hw)
set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);
list_add(&ipac->hscx[i].bch.ch.list,
&ipac->isac.dch.dev.bchannels);
- mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM);
+ mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM,
+ ipac->hscx[i].fifo_size);
ipac->hscx[i].bch.ch.nr = i + 1;
ipac->hscx[i].bch.ch.send = &hscx_l2l1;
ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 8db914a..202bd92 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1683,7 +1683,7 @@ mISDNisar_init(struct isar_hw *isar, void *hw)
isar->hw = hw;
for (i = 0; i < 2; i++) {
isar->ch[i].bch.nr = i + 1;
- mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM);
+ mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, -1);
isar->ch[i].bch.ch.nr = i + 1;
isar->ch[i].bch.ch.send = &isar_l2l1;
isar->ch[i].bch.ch.ctrl = isar_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index fd421e7..3c5d704 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -1020,7 +1020,7 @@ setup_instance(struct tiger_hw *card)
for (i = 0; i < 2; i++) {
card->bc[i].bch.nr = i + 1;
set_channelmap(i + 1, card->isac.dch.dev.channelmap);
- mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+ mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, -1);
card->bc[i].bch.hw = card;
card->bc[i].bch.ch.send = nj_l2l1B;
card->bc[i].bch.ch.ctrl = nj_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 0424652..a506018 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1312,7 +1312,7 @@ setup_instance(struct w6692_hw *card)
card->dch.hw = card;
card->dch.dev.nrbchan = 2;
for (i = 0; i < 2; i++) {
- mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+ mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, -1);
card->bc[i].bch.hw = card;
card->bc[i].bch.nr = i + 1;
card->bc[i].bch.ch.nr = i + 1;
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index a250244..467518c 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -81,7 +81,7 @@ mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf)
EXPORT_SYMBOL(mISDN_initdchannel);
int
-mISDN_initbchannel(struct bchannel *ch, int maxlen)
+mISDN_initbchannel(struct bchannel *ch, int maxlen, int minlen)
{
ch->Flags = 0;
ch->maxlen = maxlen;
@@ -89,6 +89,7 @@ mISDN_initbchannel(struct bchannel *ch, int maxlen)
ch->rx_skb = NULL;
ch->tx_skb = NULL;
ch->tx_idx = 0;
+ ch->minlen = minlen;
skb_queue_head_init(&ch->rqueue);
ch->rcount = 0;
ch->next_skb = NULL;
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 0f88acf..f68abe8 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -1420,7 +1420,7 @@ init_card(struct l1oip *hc, int pri, int bundle)
bch->nr = i + ch;
bch->slot = i + ch;
bch->debug = debug;
- mISDN_initbchannel(bch, MAX_DATA_MEM);
+ mISDN_initbchannel(bch, MAX_DATA_MEM, -1);
bch->hw = hc;
bch->ch.send = handle_bmsg;
bch->ch.ctrl = l1oip_bctrl;
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 7075753..4f97bd3 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -158,6 +158,7 @@ struct bchannel {
/* receive data */
struct sk_buff *rx_skb;
int maxlen;
+ int minlen; /* for transparent data -1 no check */
/* send data */
struct sk_buff *next_skb;
struct sk_buff *tx_skb;
@@ -172,7 +173,7 @@ struct bchannel {
};
extern int mISDN_initdchannel(struct dchannel *, int, void *);
-extern int mISDN_initbchannel(struct bchannel *, int);
+extern int mISDN_initbchannel(struct bchannel *, int, int);
extern int mISDN_freedchannel(struct dchannel *);
extern void mISDN_clear_bchannel(struct bchannel *);
extern int mISDN_freebchannel(struct bchannel *);
--
1.7.3.4
^ permalink raw reply related
* [PATCH 23/28] mISDN: Fix compiler warnings
From: Karsten Keil @ 2012-04-21 15:49 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
Newer gcc found some possible uninitialized pointer access.
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
drivers/isdn/hardware/mISDN/avmfritz.c | 11 +++++------
drivers/isdn/hardware/mISDN/hfcmulti.c | 8 ++++----
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 3781446..d0bdde3 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -404,7 +404,7 @@ static void
hdlc_empty_fifo(struct bchannel *bch, int count)
{
u32 *ptr;
- u8 *p, copy;
+ u8 *p;
u32 val, addr;
int cnt;
struct fritzcard *fc = bch->hw;
@@ -412,13 +412,12 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
pr_debug("%s: %s %d\n", fc->name, __func__, count);
if (test_bit(FLG_RX_OFF, &bch->Flags)) {
/* We drop the content, but need to read all bytes from FIFO */
- copy = 0;
+ p = NULL;
if (debug & DEBUG_HW_BFIFO)
printk(KERN_DEBUG "Dropped %d bytes - RX off\n", count);
val = (bch->nr - 1) & 1;
fc->dropcnt[val] += count;
} else {
- copy = 1;
if (!bch->rx_skb) {
if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
if (count >= bch->minlen)
@@ -441,8 +440,8 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
return;
}
p = skb_put(bch->rx_skb, count);
- ptr = (u32 *)p;
}
+ ptr = (u32 *)p;
if (AVM_FRITZ_PCIV2 == fc->type)
addr = fc->addr + (bch->nr == 2 ?
AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
@@ -453,13 +452,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
cnt = 0;
while (cnt < count) {
val = le32_to_cpu(inl(addr));
- if (copy) {
+ if (ptr) {
put_unaligned(val, ptr);
ptr++;
}
cnt += 4;
}
- if (copy && (debug & DEBUG_HW_BFIFO)) {
+ if (ptr && (debug & DEBUG_HW_BFIFO)) {
snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
bch->nr, fc->name, count);
print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 884c090..144c35a 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2456,12 +2456,12 @@ handle_timer_irq(struct hfc_multi *hc)
spin_unlock_irqrestore(&HFClock, flags);
}
if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip)) {
- if (hc->created[hc->chan[0].port] && hc->chan[ch].bch &&
+ ch = 0;
+ if (hc->created[hc->chan[ch].port] && hc->chan[ch].bch &&
test_bit(FLG_ACTIVE, &hc->chan[ch].bch->Flags)) {
ch_activ++;
- hfcmulti_tx(hc, 0);
- hfcmulti_rx(hc, 0);
- ch = 1;
+ hfcmulti_tx(hc, ch);
+ hfcmulti_rx(hc, ch);
if (hc->chan[ch].dch &&
hc->chan[ch].nt_timer > -1) {
dch = hc->chan[ch].dch;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 18/28] mISDN: Cleanup channel also if it already was deactivated
From: Karsten Keil @ 2012-03-18 13:50 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
If a channel was closed after it was deactivated it
could happen that something was not proper resetted.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/hardware/mISDN/avmfritz.c | 12 ++++--------
drivers/isdn/hardware/mISDN/hfcmulti.c | 3 +--
drivers/isdn/hardware/mISDN/hfcpci.c | 3 +--
drivers/isdn/hardware/mISDN/hfcsusb.c | 3 +--
drivers/isdn/hardware/mISDN/mISDNipac.c | 13 ++++---------
drivers/isdn/hardware/mISDN/mISDNisar.c | 13 ++++---------
drivers/isdn/hardware/mISDN/netjet.c | 12 ++++--------
drivers/isdn/hardware/mISDN/w6692.c | 13 ++++---------
8 files changed, 23 insertions(+), 49 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index c0b8c96..e76e1ba 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -839,14 +839,10 @@ avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags)) {
- spin_lock_irqsave(&fc->lock, flags);
- mISDN_freebchannel(bch);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- modehdlc(bch, ISDN_P_NONE);
- spin_unlock_irqrestore(&fc->lock, flags);
- }
+ spin_lock_irqsave(&fc->lock, flags);
+ mISDN_freebchannel(bch);
+ modehdlc(bch, ISDN_P_NONE);
+ spin_unlock_irqrestore(&fc->lock, flags);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 4ae6f8e..e91f82a 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3859,8 +3859,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);
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index e2c83a2..9262136 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1581,8 +1581,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
break;
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags))
- deactivate_bchannel(bch);
+ deactivate_bchannel(bch);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 8cde2a0..add28ac 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1836,8 +1836,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags))
- deactivate_bchannel(bch);
+ deactivate_bchannel(bch);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 884369f..4c1937b 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1416,15 +1416,10 @@ hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags)) {
- spin_lock_irqsave(hx->ip->hwlock, flags);
- mISDN_freebchannel(bch);
- hscx_mode(hx, ISDN_P_NONE);
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
- } else {
- skb_queue_purge(&bch->rqueue);
- bch->rcount = 0;
- }
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ mISDN_freebchannel(bch);
+ hscx_mode(hx, ISDN_P_NONE);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(hx->ip->owner);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 9a6da6e..af9a966 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1603,15 +1603,10 @@ isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags)) {
- spin_lock_irqsave(ich->is->hwlock, flags);
- mISDN_freebchannel(bch);
- modeisar(ich, ISDN_P_NONE);
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- } else {
- skb_queue_purge(&bch->rqueue);
- bch->rcount = 0;
- }
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ mISDN_freebchannel(bch);
+ modeisar(ich, ISDN_P_NONE);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(ich->is->owner);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index c726e09..0dccda8 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -808,14 +808,10 @@ nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags)) {
- spin_lock_irqsave(&card->lock, flags);
- mISDN_freebchannel(bch);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- mode_tiger(bc, ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- }
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_freebchannel(bch);
+ mode_tiger(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 2183357..dec013e1 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1058,15 +1058,10 @@ w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
- if (test_bit(FLG_ACTIVE, &bch->Flags)) {
- spin_lock_irqsave(&card->lock, flags);
- mISDN_freebchannel(bch);
- w6692_mode(bc, ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- } else {
- skb_queue_purge(&bch->rqueue);
- bch->rcount = 0;
- }
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_freebchannel(bch);
+ w6692_mode(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
ch->protocol = ISDN_P_NONE;
ch->peer = NULL;
module_put(THIS_MODULE);
--
1.7.3.4
^ permalink raw reply related
* [PATCH 19/28] mISDN: Early confirm for transparent data
From: Karsten Keil @ 2012-04-21 15:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev, isdn4linux
It is better to send a confirm early, less TX underuns will
happen.
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
drivers/isdn/hardware/mISDN/avmfritz.c | 7 ++-----
drivers/isdn/hardware/mISDN/hfcmulti.c | 9 ++-------
drivers/isdn/hardware/mISDN/hfcpci.c | 7 ++-----
drivers/isdn/hardware/mISDN/hfcsusb.c | 6 ------
drivers/isdn/hardware/mISDN/mISDNipac.c | 7 ++-----
drivers/isdn/hardware/mISDN/mISDNisar.c | 7 ++-----
drivers/isdn/hardware/mISDN/netjet.c | 7 ++-----
drivers/isdn/hardware/mISDN/w6692.c | 7 ++-----
drivers/isdn/mISDN/hwchannel.c | 5 +++--
9 files changed, 17 insertions(+), 45 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index e76e1ba..c773a7f 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -670,11 +670,8 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
id = hh->id; /* skb can be freed */
hdlc_fill_fifo(bch);
ret = 0;
- spin_unlock_irqrestore(&fc->lock, flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&fc->lock, flags);
+ }
+ spin_unlock_irqrestore(&fc->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&fc->lock, flags);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index e91f82a..d826586 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3586,13 +3586,8 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
/* 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)
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 9262136..6a0d964 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1702,11 +1702,8 @@ hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
id = hh->id; /* skb can be freed */
hfcpci_fill_fifo(bch);
ret = 0;
- spin_unlock_irqrestore(&hc->lock, flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&hc->lock, flags);
+ }
+ spin_unlock_irqrestore(&hc->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&hc->lock, flags);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index add28ac..404184a 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -227,12 +227,6 @@ hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n",
hw->name, __func__, ret);
if (ret > 0) {
- /*
- * other l1 drivers don't send early confirms on
- * transp data, but hfcsusb does because tx_next
- * skb is needed in tx_iso_complete()
- */
- queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
ret = 0;
}
return ret;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 4c1937b..d301d8c 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1349,11 +1349,8 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
id = hh->id; /* skb can be freed */
ret = 0;
hscx_fill_fifo(hx);
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ }
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(hx->ip->hwlock, flags);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index af9a966..8db914a 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1490,11 +1490,8 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
id = hh->id; /* skb can be freed */
ret = 0;
isar_fill_fifo(ich);
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(ich->is->hwlock, flags);
+ }
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(ich->is->hwlock, flags);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index 0dccda8..fd421e7 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -743,11 +743,8 @@ nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
id = hh->id; /* skb can be freed */
fill_dma(bc);
ret = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&card->lock, flags);
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index dec013e1..0424652 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -955,11 +955,8 @@ w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
id = hh->id; /* skb can be freed */
ret = 0;
W6692_fill_Bfifo(bc);
- spin_unlock_irqrestore(&card->lock, flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&card->lock, flags);
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index c74c363..a250244 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -305,8 +305,8 @@ get_next_bframe(struct bchannel *bch)
if (bch->tx_skb) {
bch->next_skb = NULL;
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- confirm_Bsend(bch); /* not for transparent */
+ /* confirm imediately to allow next data */
+ confirm_Bsend(bch);
return 1;
} else {
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
@@ -395,6 +395,7 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)
/* write to fifo */
ch->tx_skb = skb;
ch->tx_idx = 0;
+ confirm_Bsend(ch);
return 1;
}
}
--
1.7.3.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox