From 4641d5b396bb35599b19b6653057513e7a8d61b1 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Mon, 6 May 2013 12:33:52 -0500 Subject: [PATCH] wct4xxp: Companding on VPM needs to be changed when switching linemodes. If a user switches linemode with sysfs, the VPM would never switch the companding mode to alaw, and the result would be extreme static on all channels of the span when the VPM is enabeld. Now if the deflaw of the span has changed when an echocan is created, the companding mode of the VPM channel is changed. Signed-off-by: Shaun Ruffell --- drivers/dahdi/wct4xxp/base.c | 60 +++++++++++++++++-------------- drivers/dahdi/wct4xxp/vpm450m.c | 62 +++++++++++++++++++++++++++++++-- drivers/dahdi/wct4xxp/vpm450m.h | 2 ++ 3 files changed, 96 insertions(+), 28 deletions(-) diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c index 2b7c4a1..1ed10b1 100644 --- a/drivers/dahdi/wct4xxp/base.c +++ b/drivers/dahdi/wct4xxp/base.c @@ -390,7 +390,7 @@ static inline bool is_pcie(const struct t4 *wc) static inline bool has_e1_span(const struct t4 *wc) { - return (wc->t1e1) != 0; + return (wc->t1e1 > 0); } static inline bool is_octal(const struct t4 *wc) @@ -1121,6 +1121,7 @@ static int t4_echocan_create(struct dahdi_chan *chan, int channel; const struct dahdi_echocan_ops *ops; const struct dahdi_echocan_features *features; + const bool alaw = (chan->span->deflaw == 2); if (!vpmsupport || !wc->vpm) return -ENODEV; @@ -1141,19 +1142,19 @@ static int t4_echocan_create(struct dahdi_chan *chan, channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; - if (wc->vpm) { - if (is_octal(wc)) - channel = channel << 3; - else - channel = channel << 2; - channel |= chan->span->offset; - if (debug & DEBUG_ECHOCAN) - dev_notice(&wc->dev->dev, "echocan: Card is %d, " - "Channel is %d, Span is %d, offset is %d " - "length %d\n", wc->num, chan->chanpos, - chan->span->offset, channel, ecp->tap_length); - vpm450m_setec(wc->vpm, channel, ecp->tap_length); + if (is_octal(wc)) + channel = channel << 3; + else + channel = channel << 2; + channel |= chan->span->offset; + if (debug & DEBUG_ECHOCAN) { + dev_notice(&wc->dev->dev, + "echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n", + wc->num, chan->chanpos, chan->span->offset, + channel, ecp->tap_length); } + vpm450m_set_alaw_companding(wc->vpm, channel, alaw); + vpm450m_setec(wc->vpm, channel, ecp->tap_length); return 0; } @@ -1162,23 +1163,23 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec struct t4 *wc = chan->pvt; int channel; - memset(ec, 0, sizeof(*ec)); + if (!wc->vpm) + return; + memset(ec, 0, sizeof(*ec)); channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; - if (wc->vpm) { - if (is_octal(wc)) - channel = channel << 3; - else - channel = channel << 2; - channel |= chan->span->offset; - if (debug & DEBUG_ECHOCAN) - dev_notice(&wc->dev->dev, "echocan: Card is %d, " - "Channel is %d, Span is %d, offset is %d " - "length 0\n", wc->num, chan->chanpos, - chan->span->offset, channel); - vpm450m_setec(wc->vpm, channel, 0); + if (is_octal(wc)) + channel = channel << 3; + else + channel = channel << 2; + channel |= chan->span->offset; + if (debug & DEBUG_ECHOCAN) { + dev_notice(&wc->dev->dev, + "echocan: Card is %d, Channel is %d, Span is %d, offset is %d length 0\n", + wc->num, chan->chanpos, chan->span->offset, channel); } + vpm450m_setec(wc->vpm, channel, 0); } #endif @@ -2225,6 +2226,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) int res = 0; enum linemode mode; const char *old_name; + static DEFINE_MUTEX(linemode_lock); dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, dahdi_spantype2str(linemode)); @@ -2232,22 +2234,27 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) if (span->spantype == linemode) return 0; + /* Do not allow the t1e1 member to be changed by multiple threads. */ + mutex_lock(&linemode_lock); old_name = dahdi_spantype2str(span->spantype); switch (linemode) { case SPANTYPE_DIGITAL_T1: dev_info(&wc->dev->dev, "Changing from %s to T1 line mode.\n", old_name); mode = T1; + wc->t1e1 &= ~(1 << span->offset); break; case SPANTYPE_DIGITAL_E1: dev_info(&wc->dev->dev, "Changing from %s to E1 line mode.\n", old_name); mode = E1; + wc->t1e1 |= (1 << span->offset); break; case SPANTYPE_DIGITAL_J1: dev_info(&wc->dev->dev, "Changing from %s to J1 line mode.\n", old_name); mode = J1; + wc->t1e1 &= ~(1 << span->offset); break; default: dev_err(&wc->dev->dev, @@ -2261,6 +2268,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) dahdi_init_span(span); } + mutex_unlock(&linemode_lock); return res; } diff --git a/drivers/dahdi/wct4xxp/vpm450m.c b/drivers/dahdi/wct4xxp/vpm450m.c index f332f01..45d84fb 100644 --- a/drivers/dahdi/wct4xxp/vpm450m.c +++ b/drivers/dahdi/wct4xxp/vpm450m.c @@ -177,6 +177,7 @@ struct vpm450m { #define FLAG_DTMF (1 << 0) #define FLAG_MUTE (1 << 1) #define FLAG_ECHO (1 << 2) +#define FLAG_ALAW (1 << 3) static unsigned int tones[] = { SOUT_DTMF_1, @@ -216,6 +217,50 @@ static unsigned int tones[] = { ROUT_G168_1100GB_ON, }; +void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, int channel, + bool alaw) +{ + tOCT6100_CHANNEL_MODIFY *modify; + UINT32 ulResult; + UINT32 law_to_use = (alaw) ? cOCT6100_PCM_A_LAW : + cOCT6100_PCM_U_LAW; + + if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { + pr_err("Channel out of bounds in %s\n", __func__); + return; + } + /* If we're already in this companding mode, no need to do anything. */ + if (alaw == ((vpm450m->chanflags[channel] & FLAG_ALAW) > 0)) + return; + + modify = kzalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC); + if (!modify) { + pr_notice("Unable to allocate memory for setec!\n"); + return; + } + + Oct6100ChannelModifyDef(modify); + modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel]; + modify->fTdmConfigModified = TRUE; + modify->TdmConfig.ulSinPcmLaw = law_to_use; + modify->TdmConfig.ulRinPcmLaw = law_to_use; + modify->TdmConfig.ulSoutPcmLaw = law_to_use; + modify->TdmConfig.ulRoutPcmLaw = law_to_use; + ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify); + if (ulResult != GENERIC_OK) { + pr_notice("Failed to apply echo can changes on channel %d %d %08x!\n", + vpm450m->aulEchoChanHndl[channel], channel, ulResult); + } else { + pr_info("Changed companding on channel %d to %s.\n", channel, + (alaw) ? "alaw" : "ulaw"); + if (alaw) + vpm450m->chanflags[channel] |= FLAG_ALAW; + else + vpm450m->chanflags[channel] &= ~(FLAG_ALAW); + } + kfree(modify); +} + static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode) { tOCT6100_CHANNEL_MODIFY *modify; @@ -248,6 +293,11 @@ void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute) tOCT6100_CHANNEL_MODIFY *modify; UINT32 ulResult; + if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { + pr_err("Channel out of bounds in %s\n", __func__); + return; + } + modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL); if (!modify) { printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setdtmf!\n"); @@ -286,6 +336,11 @@ void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute) void vpm450m_setec(struct vpm450m *vpm450m, int channel, int eclen) { + if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { + pr_err("Channel out of bounds in %s\n", __func__); + return; + } + if (eclen) { vpm450m->chanflags[channel] |= FLAG_ECHO; vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); @@ -524,10 +579,13 @@ struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct f * therefore, the lower 2 bits tell us which span this * timeslot/channel */ - if (isalaw[x & mask]) + if (isalaw[x & mask]) { law = cOCT6100_PCM_A_LAW; - else + vpm450m->chanflags[x] |= FLAG_ALAW; + } else { law = cOCT6100_PCM_U_LAW; + vpm450m->chanflags[x] &= ~(FLAG_ALAW); + } Oct6100ChannelOpenDef(ChannelOpen); ChannelOpen->pulChannelHndl = &vpm450m->aulEchoChanHndl[x]; ChannelOpen->ulUserChanId = x; diff --git a/drivers/dahdi/wct4xxp/vpm450m.h b/drivers/dahdi/wct4xxp/vpm450m.h index 735a2cc..adf4150 100644 --- a/drivers/dahdi/wct4xxp/vpm450m.h +++ b/drivers/dahdi/wct4xxp/vpm450m.h @@ -39,5 +39,7 @@ void vpm450m_setdtmf(struct vpm450m *instance, int channel, int dtmfdetect, int int vpm450m_checkirq(struct vpm450m *vpm450m); int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start); void release_vpm450m(struct vpm450m *instance); +void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, + int channel, bool alaw); #endif