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 <sruffell@digium.com>

Conflicts:
	drivers/dahdi/wct4xxp/base.c
This commit is contained in:
Shaun Ruffell 2013-05-06 12:33:52 -05:00
parent d5410c2fde
commit 7c442a119a
3 changed files with 95 additions and 28 deletions

View File

@ -394,7 +394,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)
@ -1125,6 +1125,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;
@ -1145,19 +1146,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 (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;
}
@ -1166,23 +1167,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 (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
@ -2228,23 +2229,28 @@ static int t4_set_linemode(struct dahdi_span *span, const char *linemode)
struct t4 *wc = ts->owner;
int res = 0;
enum linemode mode;
static DEFINE_MUTEX(linemode_lock);
dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, linemode);
if (!strcasecmp(span->spantype, linemode))
return 0;
mutex_lock(&linemode_lock);
if (!strcasecmp(linemode, "t1")) {
dev_info(&wc->dev->dev,
"Changing from %s to T1 line mode.\n", span->spantype);
wc->t1e1 &= ~(1UL << span->offset);
mode = T1;
} else if (!strcasecmp(linemode, "e1")) {
dev_info(&wc->dev->dev,
"Changing from %s to E1 line mode.\n", span->spantype);
wc->t1e1 |= (1UL << span->offset);
mode = E1;
} else if (!strcasecmp(linemode, "j1")) {
dev_info(&wc->dev->dev,
"Changing from %s to J1 line mode.\n", span->spantype);
wc->t1e1 &= ~(1UL << span->offset);
mode = J1;
} else {
dev_err(&wc->dev->dev,
@ -2258,6 +2264,7 @@ static int t4_set_linemode(struct dahdi_span *span, const char *linemode)
dahdi_init_span(span);
}
mutex_unlock(&linemode_lock);
return res;
}

View File

@ -181,6 +181,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,
@ -220,6 +221,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;
@ -252,6 +297,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");
@ -290,6 +340,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);
@ -528,10 +583,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;

View File

@ -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