summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--README17
-rw-r--r--drivers/dahdi/dahdi-base.c250
-rw-r--r--drivers/dahdi/dahdi_dummy.c2
-rw-r--r--drivers/dahdi/dahdi_dynamic.c2
-rw-r--r--drivers/dahdi/firmware/Makefile2
-rw-r--r--drivers/dahdi/hpec/dahdi_echocan_hpec.c8
-rw-r--r--drivers/dahdi/proslic.h17
-rw-r--r--drivers/dahdi/voicebus/GpakCust.c8
-rw-r--r--drivers/dahdi/voicebus/GpakCust.h2
-rw-r--r--drivers/dahdi/voicebus/voicebus.c848
-rw-r--r--drivers/dahdi/voicebus/voicebus.h12
-rw-r--r--drivers/dahdi/wcb4xxp/base.c251
-rw-r--r--drivers/dahdi/wcb4xxp/wcb4xxp.h16
-rw-r--r--drivers/dahdi/wcfxo.c12
-rw-r--r--drivers/dahdi/wct4xxp/base.c100
-rw-r--r--drivers/dahdi/wct4xxp/wct4xxp-diag.c2
-rw-r--r--drivers/dahdi/wctc4xxp/base.c5
-rw-r--r--drivers/dahdi/wctdm.c227
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c527
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h22
-rw-r--r--drivers/dahdi/wcte12xp/base.c119
-rw-r--r--drivers/dahdi/wcte12xp/wcte12xp.h9
-rw-r--r--drivers/dahdi/xpp/xdefs.h5
-rw-r--r--include/dahdi/kernel.h10
-rw-r--r--include/dahdi/user.h13
26 files changed, 1694 insertions, 795 deletions
diff --git a/Makefile b/Makefile
index 962883b..5f86412 100644
--- a/Makefile
+++ b/Makefile
@@ -128,8 +128,7 @@ install-include:
for hdr in $(INST_HEADERS); do \
install -D -m 644 include/dahdi/$$hdr $(DESTDIR)/usr/include/dahdi/$$hdr; \
done
- -@rm -f $(DESTDIR)/usr/include/zaptel/*.h
- -@rmdir $(DESTDIR)/usr/include/zaptel
+ @rm -rf $(DESTDIR)/usr/include/zaptel
uninstall-include:
for hdr in $(INST_HEADERS); do \
diff --git a/README b/README
index c8d090d..ad6a421 100644
--- a/README
+++ b/README
@@ -528,22 +528,17 @@ cost.
Known Issues
------------
-Removing echocan modules
-~~~~~~~~~~~~~~~~~~~~~~~~
-Before unloading an echo-canceller module you must remove an reference to it.
-Using 'etc/init.d/dahdi stop' is the preferred method.
-
-However if, for some reason, you want to unload just a single dahdi_echocan_*
-module that you use, you must first edit /etc/dahdi/system.conf and change any
-echocan lines referring to it to refer to a different echo canceller module.
-
-https://issues.asterisk.org/view.php?id=15327[0015327: oops after removing an echocan module that is in use]
+KB1 does not function when echocancel > 128
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+KB1 was not designed to function at greater than 128 taps, and if configured
+this way, will result in the destruction of audio. Ideally DAHDI would return
+an error when a KB1 echocanceller is configured with greater than 128 taps.
Reporting Bugs
--------------
Please report bug and patches to the Asterisk bug tracker at
-http://bugs.digium.com in the "DAHDI" category.
+http://issues.asterisk.org in the "DAHDI" category.
Links
-----
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index cb1b1c1..6ab8636 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -78,6 +78,10 @@
#include "hpec/hpec_user.h"
+#if defined(EMPULSE) && defined(EMFLASH)
+#error "You cannot define both EMPULSE and EMFLASH"
+#endif
+
/* Get helper arithmetic */
#include "arith.h"
#if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP)
@@ -184,13 +188,6 @@ static struct class_simple *dahdi_class = NULL;
#define class_destroy class_simple_destroy
#endif
-/*
- * See issue http://bugs.digium.com/view.php?id=13504 for more information.
- * on why reference counting on the echo canceller modules is disabled
- * currently.
- */
-#undef USE_ECHOCAN_REFCOUNT
-
static int deftaps = 64;
static int debug;
@@ -397,7 +394,6 @@ static LIST_HEAD(ecfactory_list);
struct ecfactory {
const struct dahdi_echocan_factory *ec;
- struct module *owner;
struct list_head list;
};
@@ -405,6 +401,8 @@ int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec)
{
struct ecfactory *cur;
+ WARN_ON(!ec->owner);
+
write_lock(&ecfactory_list_lock);
/* make sure it isn't already registered */
@@ -1122,18 +1120,13 @@ retry:
list_for_each_entry(cur, &ecfactory_list, list) {
if (!strcmp(name_upper, cur->ec->name)) {
-#ifdef USE_ECHOCAN_REFCOUNT
- if (try_module_get(cur->owner)) {
+ if (try_module_get(cur->ec->owner)) {
read_unlock(&ecfactory_list_lock);
return cur->ec;
} else {
read_unlock(&ecfactory_list_lock);
return NULL;
}
-#else
- read_unlock(&ecfactory_list_lock);
- return cur->ec;
-#endif
}
}
@@ -1159,10 +1152,8 @@ retry:
static void release_echocan(const struct dahdi_echocan_factory *ec)
{
-#ifdef USE_ECHOCAN_REFCOUNT
if (ec)
module_put(ec->owner);
-#endif
}
/**
@@ -1878,6 +1869,8 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan)
might_sleep();
+ release_echocan(chan->ec_factory);
+
#ifdef CONFIG_DAHDI_NET
if (chan->flags & DAHDI_FLAG_NETDEV) {
unregister_hdlc_device(chan->hdlcnetdev->netdev);
@@ -2304,7 +2297,7 @@ static void dahdi_rbs_sethook(struct dahdi_chan *chan, int txsig, int txstate,
if (!chan->span)
return;
- if (!chan->span->flags & DAHDI_FLAG_RBS) {
+ if (!(chan->span->flags & DAHDI_FLAG_RBS)) {
module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state on non-RBS channel %s\n", chan->name);
return;
}
@@ -3462,16 +3455,136 @@ static int dahdi_timer_ioctl(struct inode *node, struct file *file, unsigned int
return 0;
}
+static int dahdi_ioctl_getgains(struct inode *node, struct file *file,
+ unsigned int cmd, unsigned long data, int unit)
+{
+ int res = 0;
+ struct dahdi_gains *gain;
+ int i, j;
+
+ gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+ if (!gain)
+ return -ENOMEM;
+
+ if (copy_from_user(gain, (struct dahdi_gains *)data, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+ i = gain->chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i)
+ i = unit;
+
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+
+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+ gain->chan = i; /* put the span # in here */
+ for (j = 0; j < 256; ++j) {
+ gain->txgain[j] = chans[i]->txgain[j];
+ gain->rxgain[j] = chans[i]->rxgain[j];
+ }
+ if (copy_to_user((struct dahdi_gains *)data, gain, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+cleanup:
+
+ kfree(gain);
+ return res;
+}
+
+static int dahdi_ioctl_setgains(struct inode *node, struct file *file,
+ unsigned int cmd, unsigned long data, int unit)
+{
+ int res = 0;
+ struct dahdi_gains *gain;
+ unsigned char *txgain, *rxgain;
+ int i, j;
+ unsigned long flags;
+ const int GAIN_TABLE_SIZE = sizeof(defgain);
+
+ gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+ if (!gain)
+ return -ENOMEM;
+
+ if (copy_from_user(gain, (struct dahdi_gains *)data, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+ i = gain->chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i)
+ i = unit;
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+
+ rxgain = kzalloc(GAIN_TABLE_SIZE*2, GFP_KERNEL);
+ if (!rxgain) {
+ res = -ENOMEM;
+ goto cleanup;
+ }
+
+ gain->chan = i; /* put the span # in here */
+ txgain = rxgain + GAIN_TABLE_SIZE;
+
+ for (j = 0; j < GAIN_TABLE_SIZE; ++j) {
+ rxgain[j] = gain->rxgain[j];
+ txgain[j] = gain->txgain[j];
+ }
+
+ if (!memcmp(rxgain, defgain, GAIN_TABLE_SIZE) &&
+ !memcmp(txgain, defgain, GAIN_TABLE_SIZE)) {
+ kfree(rxgain);
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 0;
+ chans[i]->rxgain = defgain;
+ chans[i]->txgain = defgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ } else {
+ /* This is a custom gain setting */
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 1;
+ chans[i]->rxgain = rxgain;
+ chans[i]->txgain = txgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ }
+
+ if (copy_to_user((struct dahdi_gains *)data, gain, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+cleanup:
+
+ kfree(gain);
+ return res;
+}
+
static int dahdi_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit)
{
union {
- struct dahdi_gains gain;
struct dahdi_spaninfo spaninfo;
struct dahdi_params param;
} stack;
struct dahdi_chan *chan;
unsigned long flags;
- unsigned char *txgain, *rxgain;
int i,j;
int return_master = 0;
size_t size_to_copy;
@@ -3597,68 +3710,9 @@ static int dahdi_common_ioctl(struct inode *node, struct file *file, unsigned in
break;
case DAHDI_GETGAINS_V1: /* Intentional drop through. */
case DAHDI_GETGAINS: /* get gain stuff */
- if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain)))
- return -EFAULT;
- i = stack.gain.chan; /* get channel no */
- /* if zero, use current channel no */
- if (!i) i = unit;
- /* make sure channel number makes sense */
- if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
-
- if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
- stack.gain.chan = i; /* put the span # in here */
- for (j=0;j<256;j++) {
- stack.gain.txgain[j] = chans[i]->txgain[j];
- stack.gain.rxgain[j] = chans[i]->rxgain[j];
- }
- if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain)))
- return -EFAULT;
- break;
+ return dahdi_ioctl_getgains(node, file, cmd, data, unit);
case DAHDI_SETGAINS: /* set gain stuff */
- if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain)))
- return -EFAULT;
- i = stack.gain.chan; /* get channel no */
- /* if zero, use current channel no */
- if (!i) i = unit;
- /* make sure channel number makes sense */
- if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
- if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
-
- if (!(rxgain = kmalloc(512, GFP_KERNEL)))
- return -ENOMEM;
-
- stack.gain.chan = i; /* put the span # in here */
- txgain = rxgain + 256;
-
- for (j=0;j<256;j++) {
- rxgain[j] = stack.gain.rxgain[j];
- txgain[j] = stack.gain.txgain[j];
- }
-
- if (!memcmp(rxgain, defgain, 256) &&
- !memcmp(txgain, defgain, 256)) {
- if (rxgain)
- kfree(rxgain);
- spin_lock_irqsave(&chans[i]->lock, flags);
- if (chans[i]->gainalloc)
- kfree(chans[i]->rxgain);
- chans[i]->gainalloc = 0;
- chans[i]->rxgain = defgain;
- chans[i]->txgain = defgain;
- spin_unlock_irqrestore(&chans[i]->lock, flags);
- } else {
- /* This is a custom gain setting */
- spin_lock_irqsave(&chans[i]->lock, flags);
- if (chans[i]->gainalloc)
- kfree(chans[i]->rxgain);
- chans[i]->gainalloc = 1;
- chans[i]->rxgain = rxgain;
- chans[i]->txgain = txgain;
- spin_unlock_irqrestore(&chans[i]->lock, flags);
- }
- if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain)))
- return -EFAULT;
- break;
+ return dahdi_ioctl_setgains(node, file, cmd, data, unit);
case DAHDI_SPANSTAT:
size_to_copy = sizeof(struct dahdi_spaninfo);
if (copy_from_user(&stack.spaninfo, (struct dahdi_spaninfo *) data, size_to_copy))
@@ -3877,6 +3931,13 @@ static int dahdi_ctl_ioctl(struct inode *inode, struct file *file, unsigned int
spin_lock_irqsave(&spans[j]->chans[x]->lock, flags);
dahdi_hangup(spans[j]->chans[x]);
spin_unlock_irqrestore(&spans[j]->chans[x]->lock, flags);
+ /*
+ * Set the rxhooksig back to
+ * DAHDI_RXSIG_INITIAL so that new events are
+ * queued on the channel with the actual
+ * recieved hook state.
+ *
+ */
spans[j]->chans[x]->rxhooksig = DAHDI_RXSIG_INITIAL;
}
}
@@ -3972,9 +4033,6 @@ static int dahdi_ctl_ioctl(struct inode *inode, struct file *file, unsigned int
if ((sigcap & ch.sigtype) != ch.sigtype)
res = -EINVAL;
- if (!res && chans[ch.chan]->span->chanconfig)
- res = chans[ch.chan]->span->chanconfig(chans[ch.chan], ch.sigtype);
-
if (chans[ch.chan]->master != chans[ch.chan]) {
struct dahdi_chan *oldmaster = chans[ch.chan]->master;
@@ -4045,6 +4103,12 @@ static int dahdi_ctl_ioctl(struct inode *inode, struct file *file, unsigned int
else
chans[ch.chan]->flags &= ~DAHDI_FLAG_MTP2;
}
+
+ if (!res && chans[ch.chan]->span->chanconfig) {
+ res = chans[ch.chan]->span->chanconfig(chans[ch.chan],
+ ch.sigtype);
+ }
+
#ifdef CONFIG_DAHDI_NET
if (!res &&
(newmaster == chans[ch.chan]) &&
@@ -4963,14 +5027,12 @@ static int ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams
ret = chan->span->echocan_create(chan, ecp, params, &ec);
if ((ret == -ENODEV) && chan->ec_factory) {
-#ifdef USE_ECHOCAN_REFCOUNT
/* try to get another reference to the module providing
this channel's echo canceler */
if (!try_module_get(chan->ec_factory->owner)) {
module_printk(KERN_ERR, "Cannot get a reference to the '%s' echo canceler\n", chan->ec_factory->name);
goto exit_with_free;
}
-#endif
/* got the reference, copy the pointer and use it for making
an echo canceler instance if possible */
@@ -7939,6 +8001,7 @@ static void coretimer_func(unsigned long param)
const unsigned long MAX_INTERVAL = 100000L;
const unsigned long FOURMS_INTERVAL = HZ/250;
const unsigned long ONESEC_INTERVAL = HZ;
+ const unsigned long MS_LIMIT = 3000;
now = current_kernel_time();
@@ -7953,6 +8016,23 @@ static void coretimer_func(unsigned long param)
mod_timer(&core_timer.timer, jiffies + FOURMS_INTERVAL);
ms_since_start = core_diff_ms(&core_timer.start_interval, &now);
+
+ /*
+ * If the system time has changed, it is possible for us to be
+ * far behind. If we are more than MS_LIMIT milliseconds
+ * behind, just reset our time base and continue so that we do
+ * not hang the system here.
+ *
+ */
+ if (unlikely((ms_since_start - atomic_read(&core_timer.count)) > MS_LIMIT)) {
+ if (printk_ratelimit())
+ module_printk(KERN_INFO, "Detected time shift.\n");
+ atomic_set(&core_timer.count, 0);
+ atomic_set(&core_timer.last_count, 0);
+ core_timer.start_interval = now;
+ return;
+ }
+
while (ms_since_start > atomic_read(&core_timer.count))
process_masterspan();
diff --git a/drivers/dahdi/dahdi_dummy.c b/drivers/dahdi/dahdi_dummy.c
index 590cc9b..66f6317 100644
--- a/drivers/dahdi/dahdi_dummy.c
+++ b/drivers/dahdi/dahdi_dummy.c
@@ -168,7 +168,7 @@ static void dahdi_dummy_timer(unsigned long param)
now = current_kernel_time();
ms_since_start = timespec_diff_ms(&ztd->start_interval, &now);
-
+
/*
* If the system time has changed, it is possible for us to be far
* behind. If we are more than MS_LIMIT milliseconds behind, just
diff --git a/drivers/dahdi/dahdi_dynamic.c b/drivers/dahdi/dahdi_dynamic.c
index 2e674fa..2a5c267 100644
--- a/drivers/dahdi/dahdi_dynamic.c
+++ b/drivers/dahdi/dahdi_dynamic.c
@@ -239,7 +239,9 @@ static void __ztdynamic_run(void)
dahdi_receive(&z->span);
dahdi_transmit(&z->span);
/* Handle all transmissions now */
+ spin_unlock_irqrestore(&dlock, flags);
ztd_sendmessage(z);
+ spin_lock_irqsave(&dlock, flags);
}
z = z->next;
}
diff --git a/drivers/dahdi/firmware/Makefile b/drivers/dahdi/firmware/Makefile
index 023279a..552435a 100644
--- a/drivers/dahdi/firmware/Makefile
+++ b/drivers/dahdi/firmware/Makefile
@@ -16,7 +16,7 @@
OCT6114_064_VERSION:=1.05.01
OCT6114_128_VERSION:=1.05.01
TC400M_VERSION:=MR6.12
-VPMADT032_VERSION:=1.17.0
+VPMADT032_VERSION:=1.20.0
FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases
diff --git a/drivers/dahdi/hpec/dahdi_echocan_hpec.c b/drivers/dahdi/hpec/dahdi_echocan_hpec.c
index 17589b8..6a98d20 100644
--- a/drivers/dahdi/hpec/dahdi_echocan_hpec.c
+++ b/drivers/dahdi/hpec/dahdi_echocan_hpec.c
@@ -114,7 +114,7 @@ static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const
hpec_channel_update(pvt->hpec, isig, iref);
}
-DECLARE_MUTEX(alloc_lock);
+DECLARE_MUTEX(license_lock);
static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec)
@@ -133,12 +133,12 @@ static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *
pvt->dahdi.ops = &my_ops;
pvt->dahdi.features = my_features;
- if (down_interruptible(&alloc_lock))
+ if (down_interruptible(&license_lock))
return -ENOTTY;
pvt->hpec = hpec_channel_alloc(ecp->tap_length);
- up(&alloc_lock);
+ up(&license_lock);
if (!pvt->hpec) {
kfree(pvt);
@@ -155,8 +155,6 @@ static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val)
return 1;
}
-DECLARE_MUTEX(license_lock);
-
static int hpec_license_ioctl(unsigned int cmd, unsigned long data)
{
struct hpec_challenge challenge;
diff --git a/drivers/dahdi/proslic.h b/drivers/dahdi/proslic.h
index ebd98bf..556643e 100644
--- a/drivers/dahdi/proslic.h
+++ b/drivers/dahdi/proslic.h
@@ -35,6 +35,23 @@ typedef struct {
// Defines
#define LPT 0X378
+/* Proslic Linefeed options for register 64 - Linefeed Control */
+#define SLIC_LF_OPEN 0x0
+#define SLIC_LF_ACTIVE_FWD 0x1
+#define SLIC_LF_OHTRAN_FWD 0x2 /* Forward On Hook Transfer */
+#define SLIC_LF_TIP_OPEN 0x3
+#define SLIC_LF_RINGING 0x4
+#define SLIC_LF_ACTIVE_REV 0x5
+#define SLIC_LF_OHTRAN_REV 0x6 /* Reverse On Hook Transfer */
+#define SLIC_LF_RING_OPEN 0x7
+
+#define SLIC_LF_SETMASK 0x7
+#define SLIC_LF_OPPENDING 0x10
+
+/* Mask used to reverse the linefeed mode between forward and
+ * reverse polarity. */
+#define SLIC_LF_REVMASK 0x4
+
#define IDA_LO 28
#define IDA_HI 29
diff --git a/drivers/dahdi/voicebus/GpakCust.c b/drivers/dahdi/voicebus/GpakCust.c
index b3228df..00fe603 100644
--- a/drivers/dahdi/voicebus/GpakCust.c
+++ b/drivers/dahdi/voicebus/GpakCust.c
@@ -370,10 +370,9 @@ int vpmadt032_echocan_create(struct vpmadt032 *vpm, int channo,
}
EXPORT_SYMBOL(vpmadt032_echocan_create);
-void vpmadt032_echocan_free(struct vpmadt032 *vpm, struct dahdi_chan *chan,
+void vpmadt032_echocan_free(struct vpmadt032 *vpm, int channo,
struct dahdi_echocan_state *ec)
{
- int channo = chan->chanpos - 1;
adt_lec_init_defaults(&vpm->desiredecstate[channo], 0);
vpm->desiredecstate[channo].nlp_type = vpm->options.vpmnlptype;
vpm->desiredecstate[channo].nlp_threshold = vpm->options.vpmnlpthresh;
@@ -525,8 +524,9 @@ vpmadt032_init(struct vpmadt032 *vpm, struct voicebus *vb)
return res;
}
vpm->curpage = -1;
- set_bit(VPM150M_SWRESET, &vpm->control);
+ dev_info(&voicebus_get_pci_dev(vb)->dev, "Booting VPMADT032\n");
+ set_bit(VPM150M_SWRESET, &vpm->control);
while (test_bit(VPM150M_SWRESET, &vpm->control))
msleep(1);
@@ -565,7 +565,7 @@ void vpmadt032_get_default_parameters(struct GpakEcanParms *p)
p->EcanDblTalkThresh = 6;
p->EcanMaxDoubleTalkThres = 40;
p->EcanNlpThreshold = DEFAULT_NLPTHRESH;
- p->EcanNlpConv = 0;
+ p->EcanNlpConv = 18;
p->EcanNlpUnConv = 12;
p->EcanNlpMaxSuppress = DEFAULT_NLPMAXSUPP;
p->EcanCngThreshold = 43;
diff --git a/drivers/dahdi/voicebus/GpakCust.h b/drivers/dahdi/voicebus/GpakCust.h
index 9b4f6a8..0546bfb 100644
--- a/drivers/dahdi/voicebus/GpakCust.h
+++ b/drivers/dahdi/voicebus/GpakCust.h
@@ -145,7 +145,7 @@ struct vpmadt032 *vpmadt032_alloc(struct vpmadt032_options *options,
void vpmadt032_free(struct vpmadt032 *vpm);
int vpmadt032_echocan_create(struct vpmadt032 *vpm, int channo,
struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p);
-void vpmadt032_echocan_free(struct vpmadt032 *vpm, struct dahdi_chan *chan,
+void vpmadt032_echocan_free(struct vpmadt032 *vpm, int channo,
struct dahdi_echocan_state *ec);
struct GpakEcanParms;
diff --git a/drivers/dahdi/voicebus/voicebus.c b/drivers/dahdi/voicebus/voicebus.c
index d794365..70a1128 100644
--- a/drivers/dahdi/voicebus/voicebus.c
+++ b/drivers/dahdi/voicebus/voicebus.c
@@ -41,8 +41,6 @@
#include "vpmadtreg.h"
#include "GpakCust.h"
-#define assert(__x__) BUG_ON(!(__x__))
-
#define INTERRUPT 0 /* Run the deferred processing in the ISR. */
#define TASKLET 1 /* Run in a tasklet. */
#define TIMER 2 /* Run in a system timer. */
@@ -56,6 +54,11 @@
#define VOICEBUS_ALLOC_FLAGS GFP_ATOMIC
#endif
+/* Define CONFIG_VOICEBUS_SYSFS to create some attributes under the pci device.
+ * This is disabled by default because it hasn't been tested on the full range
+ * of supported kernels. */
+#undef CONFIG_VOICEBUS_SYSFS
+
#if VOICEBUS_DEFERRED == TIMER
#if HZ < 1000
/* \todo Put an error message here. */
@@ -63,7 +66,7 @@
#endif
/*! The number of descriptors in both the tx and rx descriptor ring. */
-#define DRING_SIZE (1 << 5) /* Must be a power of 2 */
+#define DRING_SIZE (1 << 7) /* Must be a power of 2 */
#define DRING_MASK (DRING_SIZE-1)
/* Interrupt status' reported in SR_CSR5 */
@@ -110,10 +113,10 @@
/* In memory structure shared by the host and the adapter. */
struct voicebus_descriptor {
- u32 des0;
- u32 des1;
- u32 buffer1;
- u32 container; /* Unused */
+ volatile __le32 des0;
+ volatile __le32 des1;
+ volatile __le32 buffer1;
+ volatile __le32 container; /* Unused */
} __attribute__((packed));
struct voicebus_descriptor_list {
@@ -127,20 +130,22 @@ struct voicebus_descriptor_list {
void *pending[DRING_SIZE];
/* PCI Bus address of the descriptor list. */
dma_addr_t desc_dma;
- /*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
- unsigned int direction;
/*! The number of buffers currently submitted to the hardware. */
atomic_t count;
/*! The number of bytes to pad each descriptor for cache alignment. */
unsigned int padding;
};
-
-/*! * \brief Represents a VoiceBus interface on a Digium telephony card.
+/**
+ * struct voicebus -
+ *
+ * @tx_idle_vbb:
+ * @tx_idle_vbb_dma_addr:
+ * @max_latency: Do not allow the driver to automatically insert more than this
+ * much latency to the tdm stream by default.
+ * @count: The number of non-idle buffers that we should be expecting.
*/
struct voicebus {
- /*! Name of this card. */
- const char *board_name;
/*! The system pci device for this VoiceBus interface. */
struct pci_dev *pdev;
/*! Protects access to card registers and this structure. You should
@@ -154,6 +159,8 @@ struct voicebus {
/*! Pool to allocate memory for the tx and rx descriptor rings. */
struct voicebus_descriptor_list rxd;
struct voicebus_descriptor_list txd;
+ void *idle_vbb;
+ dma_addr_t idle_vbb_dma_addr;
/*! Level of debugging information. 0=None, 5=Insane. */
atomic_t debuglevel;
/*! Cache of buffer objects. */
@@ -186,12 +193,18 @@ struct voicebus {
struct completion stopped_completion;
/*! Flags */
unsigned long flags;
- /* \todo see about removing this... */
- u32 sdi;
/*! Number of tx buffers to queue up before enabling interrupts. */
unsigned int min_tx_buffer_count;
+ unsigned int max_latency;
+ void *vbb_stash[DRING_SIZE];
+ unsigned int count;
};
+static inline void handle_transmit(struct voicebus *vb, void *vbb)
+{
+ vb->handle_transmit(vbb, vb->context);
+}
+
/*
* Use the following macros to lock the VoiceBus interface, and it won't
* matter if the deferred processing is running inside the interrupt handler,
@@ -218,15 +231,13 @@ struct voicebus {
#define VBUNLOCK_FROM_DEFERRED(_vb_) spin_lock(&((_vb_)->lock))
#endif
-#define VB_PRINTK(_vb, _lvl, _fmt, _args...) \
- printk(KERN_##_lvl "%s: " _fmt, (_vb)->board_name, ## _args)
-
/* Bit definitions for struct voicebus.flags */
#define TX_UNDERRUN 1
#define RX_UNDERRUN 2
#define IN_DEFERRED_PROCESSING 3
#define STOP 4
#define STOPPED 5
+#define LATENCY_LOCKED 6
#if VOICEBUS_DEFERRED == WORKQUEUE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
@@ -257,32 +268,9 @@ vb_set_workqueue_priority(struct voicebus *vb)
#endif
#endif
-#ifdef DBG
-static inline int
-assert_in_vb_deferred(struct voicebus *vb)
-{
- assert(test_bit(IN_DEFERRED_PROCESSING, &vb->flags));
-}
-
-static inline void
-start_vb_deferred(struct voicebus *vb)
-{
- set_bit(IN_DEFERRED_PROCESSING, &vb->flags);
-}
-
-static inline void
-stop_vb_deferred(struct voicebus *vb)
-{
- clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
-}
-#else
-#define assert_in_vb_deferred(_x_) do {; } while (0)
-#define start_vb_deferred(_x_) do {; } while (0)
-#define stop_vb_deferred(_x_) do {; } while (0)
-#endif
-
static inline struct voicebus_descriptor *
-vb_descriptor(struct voicebus_descriptor_list *dl, int index)
+vb_descriptor(const struct voicebus_descriptor_list *dl,
+ const unsigned int index)
{
struct voicebus_descriptor *d;
d = (struct voicebus_descriptor *)((u8*)dl->desc +
@@ -298,7 +286,7 @@ vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *
struct voicebus_descriptor *d;
const u32 END_OF_RING = 0x02000000;
- assert(dl);
+ BUG_ON(!dl);
/*
* Add some padding to each descriptor to ensure that they are
@@ -324,16 +312,55 @@ vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *
d->des1 = des1;
}
d->des1 |= cpu_to_le32(END_OF_RING);
- dl->direction = direction;
atomic_set(&dl->count, 0);
return 0;
}
+#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
+#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0)
+
static int
vb_initialize_tx_descriptors(struct voicebus *vb)
{
- return vb_initialize_descriptors(
- vb, &vb->txd, 0xe4800000 | vb->framesize, DMA_TO_DEVICE);
+ int i;
+ int des1 = 0xe4800000 | vb->framesize;
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->txd;
+ const u32 END_OF_RING = 0x02000000;
+
+ WARN_ON(!dl);
+ WARN_ON((NULL == vb->idle_vbb) || (0 == vb->idle_vbb_dma_addr));
+
+ /*
+ * Add some padding to each descriptor to ensure that they are
+ * aligned on host system cache-line boundaries, but only for the
+ * cache-line sizes that we support.
+ *
+ */
+ if ((0x08 == vb->cache_line_size) || (0x10 == vb->cache_line_size) ||
+ (0x20 == vb->cache_line_size)) {
+ dl->padding = (vb->cache_line_size*sizeof(u32)) - sizeof(*d);
+ } else {
+ dl->padding = 0;
+ }
+
+ dl->desc = pci_alloc_consistent(vb->pdev,
+ (sizeof(*d) + dl->padding) *
+ DRING_SIZE, &dl->desc_dma);
+ if (!dl->desc)
+ return -ENOMEM;
+
+ memset(dl->desc, 0, (sizeof(*d) + dl->padding) * DRING_SIZE);
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ d->des1 = des1;
+ d->buffer1 = vb->idle_vbb_dma_addr;
+ dl->pending[i] = vb->idle_vbb;
+ SET_OWNED(d);
+ }
+ d->des1 |= cpu_to_le32(END_OF_RING);
+ atomic_set(&dl->count, 0);
+ return 0;
}
static int
@@ -358,10 +385,10 @@ voicebus_set_minlatency(struct voicebus *vb, unsigned int ms)
*/
#define MESSAGE "%d ms is an invalid value for minumum latency. Setting to %d ms.\n"
if (DRING_SIZE < ms) {
- VB_PRINTK(vb, WARNING, MESSAGE, ms, DRING_SIZE);
+ dev_warn(&vb->pdev->dev, MESSAGE, ms, DRING_SIZE);
return -EINVAL;
} else if (VOICEBUS_DEFAULT_LATENCY > ms) {
- VB_PRINTK(vb, WARNING, MESSAGE, ms, VOICEBUS_DEFAULT_LATENCY);
+ dev_warn(&vb->pdev->dev, MESSAGE, ms, VOICEBUS_DEFAULT_LATENCY);
return -EINVAL;
}
VBLOCK(vb);
@@ -419,6 +446,36 @@ voicebus_current_latency(struct voicebus *vb)
}
EXPORT_SYMBOL(voicebus_current_latency);
+/**
+ * voicebus_lock_latency() - Do not increase the latency during underruns.
+ *
+ */
+void voicebus_lock_latency(struct voicebus *vb)
+{
+ set_bit(LATENCY_LOCKED, &vb->flags);
+}
+EXPORT_SYMBOL(voicebus_lock_latency);
+
+/**
+ * voicebus_unlock_latency() - Bump up the latency during underruns.
+ *
+ */
+void voicebus_unlock_latency(struct voicebus *vb)
+{
+ clear_bit(LATENCY_LOCKED, &vb->flags);
+}
+EXPORT_SYMBOL(voicebus_unlock_latency);
+
+/**
+ * voicebus_is_latency_locked() - Return 1 if latency is currently locked.
+ *
+ */
+int voicebus_is_latency_locked(const struct voicebus *vb)
+{
+ return test_bit(LATENCY_LOCKED, &vb->flags);
+}
+EXPORT_SYMBOL(voicebus_is_latency_locked);
+
/*!
* \brief Read one of the hardware control registers without acquiring locks.
*/
@@ -460,18 +517,48 @@ vb_is_stopped(struct voicebus *vb)
}
static void
-vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+vb_cleanup_tx_descriptors(struct voicebus *vb)
+{
+ unsigned int i;
+ struct voicebus_descriptor_list *dl = &vb->txd;
+ struct voicebus_descriptor *d;
+
+ BUG_ON(!vb_is_stopped(vb));
+
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ if (d->buffer1 && (d->buffer1 != vb->idle_vbb_dma_addr)) {
+ WARN_ON(!dl->pending[i]);
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_TO_DEVICE);
+ voicebus_free(vb, dl->pending[i]);
+ }
+ d->buffer1 = vb->idle_vbb_dma_addr;
+ dl->pending[i] = vb->idle_vbb;
+ SET_OWNED(d);
+ }
+ /* Send out two idle buffers to start because sometimes the first buffer
+ * doesn't make it back to us. */
+ dl->head = dl->tail = 2;
+ atomic_set(&dl->count, 0);
+}
+
+static void
+vb_cleanup_rx_descriptors(struct voicebus *vb)
{
unsigned int i;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
struct voicebus_descriptor *d;
- assert(vb_is_stopped(vb));
+ BUG_ON(!vb_is_stopped(vb));
for (i = 0; i < DRING_SIZE; ++i) {
d = vb_descriptor(dl, i);
if (d->buffer1) {
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_FROM_DEVICE);
d->buffer1 = 0;
- assert(dl->pending[i]);
+ BUG_ON(!dl->pending[i]);
voicebus_free(vb, dl->pending[i]);
dl->pending[i] = NULL;
}
@@ -482,6 +569,15 @@ vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
atomic_set(&dl->count, 0);
}
+static void vb_cleanup_descriptors(struct voicebus *vb,
+ struct voicebus_descriptor_list *dl)
+{
+ if (dl == &vb->txd)
+ vb_cleanup_tx_descriptors(vb);
+ else
+ vb_cleanup_rx_descriptors(vb);
+}
+
static void
vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
{
@@ -519,30 +615,30 @@ vb_setctl(struct voicebus *vb, u32 addr, u32 val)
}
static int
-__vb_sdi_clk(struct voicebus *vb)
+__vb_sdi_clk(struct voicebus *vb, u32 *sdi)
{
unsigned int ret;
- vb->sdi &= ~CSR9_MDC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+ *sdi &= ~CSR9_MDC;
+ __vb_setctl(vb, 0x0048, *sdi);
ret = __vb_getctl(vb, 0x0048);
- vb->sdi |= CSR9_MDC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+ *sdi |= CSR9_MDC;
+ __vb_setctl(vb, 0x0048, *sdi);
return (ret & CSR9_MDI) ? 1 : 0;
}
static void
-__vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count)
+__vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count, u32 *sdi)
{
- vb->sdi &= ~CSR9_MMC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+ *sdi &= ~CSR9_MMC;
+ __vb_setctl(vb, 0x0048, *sdi);
while (count--) {
if (bits & (1 << count))
- vb->sdi |= CSR9_MDO;
+ *sdi |= CSR9_MDO;
else
- vb->sdi &= ~CSR9_MDO;
+ *sdi &= ~CSR9_MDO;
- __vb_sdi_clk(vb);
+ __vb_sdi_clk(vb, sdi);
}
}
@@ -551,13 +647,14 @@ vb_setsdi(struct voicebus *vb, int addr, u16 val)
{
LOCKS_VOICEBUS;
u32 bits;
+ u32 sdi = 0;
/* Send preamble */
bits = 0xffffffff;
VBLOCK(vb);
- __vb_sdi_sendbits(vb, bits, 32);
+ __vb_sdi_sendbits(vb, bits, 32, &sdi);
bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2;
- __vb_sdi_sendbits(vb, bits, 16);
- __vb_sdi_sendbits(vb, val, 16);
+ __vb_sdi_sendbits(vb, bits, 16, &sdi);
+ __vb_sdi_sendbits(vb, val, 16, &sdi);
VBUNLOCK(vb);
}
@@ -566,7 +663,7 @@ vb_enable_io_access(struct voicebus *vb)
{
LOCKS_VOICEBUS;
u32 reg;
- assert(vb->pdev);
+ BUG_ON(!vb->pdev);
VBLOCK(vb);
pci_read_config_dword(vb->pdev, 0x0004, &reg);
reg |= 0x00000007;
@@ -620,11 +717,12 @@ vb_reset_interface(struct voicebus *vb)
pci_access = DEFAULT_PCI_ACCESS | (0x3 << 14);
break;
default:
- if (atomic_read(&vb->debuglevel))
- VB_PRINTK(vb, WARNING, "Host system set a cache size "\
- "of %d which is not supported. " \
- "Disabling memory write line and memory read line.\n",
- vb->cache_line_size);
+ if (atomic_read(&vb->debuglevel)) {
+ dev_warn(&vb->pdev->dev, "Host system set a cache "
+ "size of %d which is not supported. "
+ "Disabling memory write line and memory "
+ "read line.\n", vb->cache_line_size);
+ }
pci_access = 0xfe584202;
break;
}
@@ -640,8 +738,8 @@ vb_reset_interface(struct voicebus *vb)
} while ((reg & 0x00000001) && time_before(jiffies, timeout));
if (reg & 0x00000001) {
- VB_PRINTK(vb, ERR, "Hardware did not come out of reset "\
- "within 100ms!");
+ dev_warn(&vb->pdev->dev, "Hardware did not come out of reset "
+ "within 100ms!");
return -EIO;
}
@@ -655,8 +753,8 @@ vb_initialize_interface(struct voicebus *vb)
{
u32 reg;
- vb_cleanup_descriptors(vb, &vb->txd);
- vb_cleanup_descriptors(vb, &vb->rxd);
+ vb_cleanup_tx_descriptors(vb);
+ vb_cleanup_rx_descriptors(vb);
/* Pass bad packets, runt packets, disable SQE function,
* store-and-forward */
@@ -689,12 +787,9 @@ vb_initialize_interface(struct voicebus *vb)
return ((reg&0x7) == 0x4) ? 0 : -EIO;
}
-#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
-#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0)
-
#ifdef DBG
static void
-dump_descriptor(struct voicebus *vb, volatile struct voicebus_descriptor *d)
+dump_descriptor(struct voicebus *vb, struct voicebus_descriptor *d)
{
VB_PRINTK(vb, DEBUG, "Displaying descriptor at address %08x\n", (unsigned int)d);
VB_PRINTK(vb, DEBUG, " des0: %08x\n", d->des0);
@@ -720,61 +815,32 @@ show_buffer(struct voicebus *vb, void *vbb)
}
#endif
-static inline int
-vb_submit(struct voicebus *vb, struct voicebus_descriptor_list *dl, void *vbb)
+/**
+ * voicebus_transmit - Queue a buffer on the hardware descriptor ring.
+ *
+ */
+int voicebus_transmit(struct voicebus *vb, void *vbb)
{
- volatile struct voicebus_descriptor *d;
- unsigned int tail = dl->tail;
- assert_in_vb_deferred(vb);
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->txd;
- d = vb_descriptor(dl, tail);
+ d = vb_descriptor(dl, dl->tail);
- if (unlikely(d->buffer1)) {
- /* Do not overwrite a buffer that is still in progress. */
- WARN_ON(1);
+ if (unlikely(d->buffer1 != vb->idle_vbb_dma_addr)) {
+ if (printk_ratelimit())
+ dev_warn(&vb->pdev->dev, "Dropping tx buffer buffer\n");
voicebus_free(vb, vbb);
- return -EBUSY;
+ return -EFAULT;
}
- dl->pending[tail] = vbb;
- dl->tail = (++tail) & DRING_MASK;
- d->buffer1 = dma_map_single(
- &vb->pdev->dev, vbb, vb->framesize, dl->direction);
+ dl->pending[dl->tail] = vbb;
+ dl->tail = (++(dl->tail)) & DRING_MASK;
+ d->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
+ vb->framesize, DMA_TO_DEVICE);
SET_OWNED(d); /* That's it until the hardware is done with it. */
atomic_inc(&dl->count);
return 0;
}
-
-static inline void*
-vb_retrieve(struct voicebus *vb, struct voicebus_descriptor_list *dl)
-{
- volatile struct voicebus_descriptor *d;
- void *vbb;
- unsigned int head = dl->head;
- assert_in_vb_deferred(vb);
- d = vb_descriptor(dl, head);
- if (d->buffer1 && !OWNED(d)) {
- dma_unmap_single(&vb->pdev->dev, d->buffer1,
- vb->framesize, dl->direction);
- vbb = dl->pending[head];
- dl->head = (++head) & DRING_MASK;
- d->buffer1 = 0;
- atomic_dec(&dl->count);
- return vbb;
- } else {
- return NULL;
- }
-}
-
-/*!
- * \brief Give a frame to the hardware to transmit.
- *
- */
-int
-voicebus_transmit(struct voicebus *vb, void *vbb)
-{
- return vb_submit(vb, &vb->txd, vbb);
-}
EXPORT_SYMBOL(voicebus_transmit);
/*!
@@ -784,7 +850,26 @@ EXPORT_SYMBOL(voicebus_transmit);
static inline int
vb_submit_rxb(struct voicebus *vb, void *vbb)
{
- return vb_submit(vb, &vb->rxd, vbb);
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
+ unsigned int tail = dl->tail;
+
+ d = vb_descriptor(dl, tail);
+
+ if (unlikely(d->buffer1)) {
+ /* Do not overwrite a buffer that is still in progress. */
+ WARN_ON(1);
+ voicebus_free(vb, vbb);
+ return -EBUSY;
+ }
+
+ dl->pending[tail] = vbb;
+ dl->tail = (++tail) & DRING_MASK;
+ d->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
+ vb->framesize, DMA_FROM_DEVICE);
+ SET_OWNED(d); /* That's it until the hardware is done with it. */
+ atomic_inc(&dl->count);
+ return 0;
}
/*!
@@ -803,13 +888,47 @@ vb_submit_rxb(struct voicebus *vb, void *vbb)
static inline void *
vb_get_completed_txb(struct voicebus *vb)
{
- return vb_retrieve(vb, &vb->txd);
+ struct voicebus_descriptor_list *dl = &vb->txd;
+ struct voicebus_descriptor *d;
+ void *vbb;
+ unsigned int head = dl->head;
+
+ d = vb_descriptor(dl, head);
+
+ if (OWNED(d) || (d->buffer1 == vb->idle_vbb_dma_addr))
+ return NULL;
+
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_TO_DEVICE);
+
+ vbb = dl->pending[head];
+ dl->head = (++head) & DRING_MASK;
+ d->buffer1 = vb->idle_vbb_dma_addr;
+ SET_OWNED(d);
+ atomic_dec(&dl->count);
+ return vbb;
}
static inline void *
vb_get_completed_rxb(struct voicebus *vb)
{
- return vb_retrieve(vb, &vb->rxd);
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
+ unsigned int head = dl->head;
+ void *vbb;
+
+ d = vb_descriptor(dl, head);
+
+ if ((0 == d->buffer1) || OWNED(d))
+ return NULL;
+
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_FROM_DEVICE);
+ vbb = dl->pending[head];
+ dl->head = (++head) & DRING_MASK;
+ d->buffer1 = 0;
+ atomic_dec(&dl->count);
+ return vbb;
}
/*!
@@ -905,7 +1024,9 @@ voicebus_start(struct voicebus *vb)
void *vbb;
int ret;
- assert(!in_interrupt());
+ WARN_ON(pci_get_drvdata(vb->pdev) != vb);
+ if (pci_get_drvdata(vb->pdev) != vb)
+ return -EFAULT;
if (!vb_is_stopped(vb))
return -EBUSY;
@@ -928,7 +1049,6 @@ voicebus_start(struct voicebus *vb)
* is known to not be running at this point, it is safe to call the
* handle transmit as if it were.
*/
- start_vb_deferred(vb);
/* Ensure that all the rx slots are ready for a buffer. */
for (i = 0; i < DRING_SIZE; ++i) {
vbb = voicebus_alloc(vb);
@@ -947,10 +1067,9 @@ voicebus_start(struct voicebus *vb)
if (unlikely(NULL == vbb))
BUG_ON(1);
else
- vb->handle_transmit(vbb, vb->context);
+ handle_transmit(vb, vbb);
}
- stop_vb_deferred(vb);
VBLOCK(vb);
clear_bit(STOP, &vb->flags);
@@ -971,7 +1090,7 @@ voicebus_start(struct voicebus *vb)
__vb_tx_demand_poll(vb);
VBUNLOCK(vb);
- assert(!vb_is_stopped(vb));
+ BUG_ON(vb_is_stopped(vb));
return 0;
}
@@ -1033,8 +1152,6 @@ vb_wait_for_completion_timeout(struct completion *x, unsigned long timeout)
int
voicebus_stop(struct voicebus *vb)
{
- assert(!in_interrupt());
-
if (vb_is_stopped(vb))
return 0;
@@ -1043,11 +1160,10 @@ voicebus_stop(struct voicebus *vb)
vb_clear_start_transmit_bit(vb);
vb_clear_start_receive_bit(vb);
if (vb_wait_for_completion_timeout(&vb->stopped_completion, HZ)) {
- assert(vb_is_stopped(vb));
+ BUG_ON(!vb_is_stopped(vb));
} else {
- VB_PRINTK(vb, WARNING, "Timeout while waiting for board to "\
- "stop.\n");
-
+ dev_warn(&vb->pdev->dev, "Timeout while waiting for board to "
+ "stop.\n");
vb_clear_start_transmit_bit(vb);
vb_clear_start_receive_bit(vb);
@@ -1063,6 +1179,24 @@ voicebus_stop(struct voicebus *vb)
}
EXPORT_SYMBOL(voicebus_stop);
+#ifdef CONFIG_VOICEBUS_SYSFS
+static ssize_t
+voicebus_current_latency_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ struct voicebus *vb = dev_get_drvdata(dev);
+ unsigned int current_latency;
+ spin_lock_irqsave(&vb->lock, flags);
+ current_latency = vb->min_tx_buffer_count;
+ spin_unlock_irqrestore(&vb->lock, flags);
+ return sprintf(buf, "%d\n", current_latency);
+}
+
+DEVICE_ATTR(voicebus_current_latency, 0444,
+ voicebus_current_latency_show, NULL);
+#endif
+
/*!
* \brief Prepare the interface for module unload.
*
@@ -1075,7 +1209,9 @@ EXPORT_SYMBOL(voicebus_stop);
void
voicebus_release(struct voicebus *vb)
{
- assert(!in_interrupt());
+#ifdef CONFIG_VOICEBUS_SYSFS
+ device_remove_file(&vb->pdev->dev, &dev_attr_voicebus_current_latency);
+#endif
/* quiesce the hardware */
voicebus_stop(vb);
@@ -1092,6 +1228,10 @@ voicebus_release(struct voicebus *vb)
/* Cleanup memory and software resources. */
vb_free_descriptors(vb, &vb->txd);
vb_free_descriptors(vb, &vb->rxd);
+ if (vb->idle_vbb_dma_addr) {
+ dma_free_coherent(&vb->pdev->dev, vb->framesize,
+ vb->idle_vbb, vb->idle_vbb_dma_addr);
+ }
kmem_cache_destroy(vb->buffer_cache);
release_region(vb->iobase, 0xff);
pci_disable_device(vb->pdev);
@@ -1100,103 +1240,291 @@ voicebus_release(struct voicebus *vb)
EXPORT_SYMBOL(voicebus_release);
static void
-__vb_increase_latency(struct voicebus *vb)
+vb_increase_latency(struct voicebus *vb, unsigned int increase)
{
- static int __warn_once = 1;
void *vbb;
- int latency;
+ int i;
- assert_in_vb_deferred(vb);
+ if (0 == increase)
+ return;
- latency = atomic_read(&vb->txd.count);
- if (DRING_SIZE == latency) {
- if (__warn_once) {
- /* We must subtract two from this number since there
- * are always two buffers in the TX FIFO.
- */
- VB_PRINTK(vb, ERR,
- "ERROR: Unable to service card within %d ms "\
- "and unable to further increase latency.\n",
- DRING_SIZE-2);
- __warn_once = 0;
- }
- } else {
- /* Because there are 2 buffers in the transmit FIFO on the
- * hardware, setting 3 ms of latency means that the host needs
- * to be able to service the cards within 1ms. This is because
- * the interface will load up 2 buffers into the TX FIFO then
- * attempt to read the 3rd descriptor. If the OWN bit isn't
- * set, then the hardware will set the TX descriptor not
- * available interrupt.
- */
- VB_PRINTK(vb, INFO, "Missed interrupt. " \
- "Increasing latency to %d ms in order to compensate.\n",
- latency+1);
- /* Set the minimum latency in case we're restarted...we don't
- * want to wait for the buffer to grow to this depth again in
- * that case.
- */
- voicebus_set_minlatency(vb, latency+1);
+ if (test_bit(LATENCY_LOCKED, &vb->flags))
+ return;
+
+ if (unlikely(increase > VOICEBUS_MAXLATENCY_BUMP))
+ increase = VOICEBUS_MAXLATENCY_BUMP;
+
+ if ((increase + vb->min_tx_buffer_count) > vb->max_latency)
+ increase = vb->max_latency - vb->min_tx_buffer_count;
+
+ /* Because there are 2 buffers in the transmit FIFO on the hardware,
+ * setting 3 ms of latency means that the host needs to be able to
+ * service the cards within 1ms. This is because the interface will
+ * load up 2 buffers into the TX FIFO then attempt to read the 3rd
+ * descriptor. If the OWN bit isn't set, then the hardware will set the
+ * TX descriptor not available interrupt. */
+
+ /* Set the minimum latency in case we're restarted...we don't want to
+ * wait for the buffer to grow to this depth again in that case. */
+ for (i = 0; i < increase; ++i) {
vbb = voicebus_alloc(vb);
+ WARN_ON(NULL == vbb);
+ if (likely(NULL != vbb))
+ handle_transmit(vb, vbb);
+ }
- if (unlikely(NULL == vbb))
- BUG_ON(1);
- else
- vb->handle_transmit(vbb, vb->context);
+ /* Set the new latency (but we want to ensure that there aren't any
+ * printks to the console, so we don't call the function) */
+ spin_lock(&vb->lock);
+ vb->min_tx_buffer_count += increase;
+ spin_unlock(&vb->lock);
+}
+static void vb_set_all_owned(struct voicebus *vb,
+ struct voicebus_descriptor_list *dl)
+{
+ int i;
+ struct voicebus_descriptor *d;
+
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ SET_OWNED(d);
}
}
-/*!
- * \brief Actually process the completed transmit and receive buffers.
+static inline void vb_set_all_tx_owned(struct voicebus *vb)
+{
+ vb_set_all_owned(vb, &vb->txd);
+}
+
+/**
+ * __vb_get_default_behind_count() - Returns how many idle buffers are loaded in tx fifo.
+ *
+ * These buffers are going to be set, but the AN983 does not clear the owned
+ * bit on the descriptors until they've actually been sent around.
*
- * NOTE: This function may be called either from a tasklet, workqueue, or
- * directly in the interrupt service routine depending on
- * VOICEBUS_DEFERRED.
+ * If you do not check for both the current and next descriptors, you could have
+ * a condition where idle buffers are being sent around, but we don't detect
+ * them because our current descriptor always points to a non-idle buffer.
*/
-static inline void
-vb_deferred(struct voicebus *vb)
+static unsigned int __vb_get_default_behind_count(const struct voicebus *vb)
{
- void *vbb;
-#ifdef DBG
- static int count;
-#endif
+ const struct voicebus_descriptor_list *const dl = &vb->txd;
+ const struct voicebus_descriptor *current_descriptor;
+ const struct voicebus_descriptor *next_descriptor;
+
+ current_descriptor = vb_descriptor(dl, dl->head);
+ if (current_descriptor->buffer1 == vb->idle_vbb_dma_addr)
+ return 2;
+
+ next_descriptor = vb_descriptor(dl, ((dl->head + 1) & DRING_MASK));
+ if (next_descriptor->buffer1 == vb->idle_vbb_dma_addr)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * vb_check_softunderrun() - Return true if the TX FIFO has underrun valid data.
+ *
+ * Returns true if we're processing the idle buffers, which means that the host
+ * was not able to keep up with the hardware. This differs from a normal
+ * underrun in that the interface chip on the board still has descriptors to
+ * transmit (just in this case, they are the idle buffers).
+ *
+ */
+static inline int vb_is_softunderrun(const struct voicebus *vb)
+{
+ return __vb_get_default_behind_count(vb) > 0;
+}
+
+/**
+ * vb_recover_tx_descriptor_list() - Recovers descriptor list
+ *
+ * Returns the number of descriptors that we're behind.
+ *
+ * Called if the [head | head + 1] pointer points to one of the idle buffers.
+ * This means that the host computer has failed to keep far enough ahead of the
+ * voicebus card. This function acks the completed idle descriptors and gets
+ * everything setup for normal operation again.
+ *
+ */
+static unsigned int vb_recover_tx_descriptor_list(struct voicebus *vb)
+{
+ struct voicebus_descriptor_list *const dl = &vb->txd;
+ struct voicebus_descriptor *d;
+ struct vbb *vbb = NULL;
+ unsigned int behind = __vb_get_default_behind_count(vb);
+ WARN_ON(0 == behind);
+
+ d = vb_descriptor(dl, dl->head);
+
+ /* If we're only behind by one descriptor, we need to wait for all
+ * descriptors to go owned so we're starting with a fresh slate. This
+ * will also means we send an additional idle buffer. */
+ if (1 == behind) {
+ unsigned long stop;
+ stop = jiffies + HZ/100;
+ while (OWNED(d) && time_after(stop, jiffies))
+ continue;
+ WARN_ON(time_before(stop, jiffies));
+ WARN_ON(d->buffer1 == vb->idle_vbb_dma_addr);
+ WARN_ON(!dl->pending[dl->head]);
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_TO_DEVICE);
+ vbb = dl->pending[dl->head];
+ atomic_dec(&dl->count);
+ --behind;
+ }
+
+ /* First complete any "idle" buffers that the hardware was to actually
+ * complete. We've already preloaded the behind variable for the idle
+ * buffers that are in progress but may not be complete. */
+ while (!OWNED(d)) {
+ d->buffer1 = vb->idle_vbb_dma_addr;
+ dl->pending[dl->head] = vb->idle_vbb;
+ SET_OWNED(d);
+ dl->head = ++dl->head & DRING_MASK;
+ d = vb_descriptor(dl, dl->head);
+ ++behind;
+ }
+
+ /* Next get a little further ahead, because the hardware will be
+ * currently working on one of the idle buffers that we can't detect is
+ * completed yet in the previous block. Set the head and tail pointers
+ * to this new position so that everything can pick up normally. */
+ dl->tail = dl->head = (dl->head + 10) & DRING_MASK;
+
+ if (NULL != vbb)
+ handle_transmit(vb, vbb);
+
+ return behind;
+}
+
+/**
+ * vb_deferred() - Manage the transmit and receive descriptor rings.
+ *
+ */
+static void vb_deferred(struct voicebus *vb)
+{
+ unsigned int buffer_count;
+ unsigned int i;
+ unsigned int idle_buffers;
+ int softunderrun;
+
int underrun = test_bit(TX_UNDERRUN, &vb->flags);
+ buffer_count = 0;
- start_vb_deferred(vb);
- if (unlikely(underrun)) {
- /* When we've underrun our FIFO, for some reason we're not
- * able to keep enough transmit descriptors pending. This can
- * happen if either interrupts or this deferred processing
- * function is not run soon enough (within 1ms when using the
- * default 3 transmit buffers to start). In this case, we'll
- * insert an additional transmit buffer onto the descriptor
- * list which decreases the sensitivity to latency, but also
- * adds more delay to the TDM and SPI data.
- */
- __vb_increase_latency(vb);
+ /* First, temporarily store any non-idle buffers that the hardware has
+ * indicated it's finished transmitting. Non idle buffers are those
+ * buffers that contain actual data and was filled out by the client
+ * driver (as of this writing, the wcte12xp or wctdm24xxp drivers) when
+ * passed up through the handle_transmit callback.
+ *
+ * On the other hand, idle buffers are "dummy" buffers that solely exist
+ * to in order to prevent the transmit descriptor ring from ever
+ * completely draining. */
+ while ((vb->vbb_stash[buffer_count] = vb_get_completed_txb(vb))) {
+ ++buffer_count;
+ if (unlikely(VOICEBUS_DEFAULT_MAXLATENCY < buffer_count)) {
+ dev_warn(&vb->pdev->dev, "Critical problem detected "
+ "in transmit ring descriptor\n");
+ if (buffer_count >= DRING_SIZE)
+ buffer_count = DRING_SIZE - 1;
+ break;
+ }
}
- /* Always handle the transmit buffers first. */
- while ((vbb = vb_get_completed_txb(vb)))
- vb->handle_transmit(vbb, vb->context);
+ vb->count += buffer_count;
+
+ /* Next, check to see if we're in a softunderrun condition.
+ *
+ * A soft under is when the hardware has possibly copied at least one of
+ * the idle buffers into it's transmit queue. Since all the buffers are
+ * nearly always owned by the hardware, the way we detect this is by
+ * checking if either of the next two buffers that we expect to complete
+ * are idle buffers. We need to check the next two, because the
+ * hardware can read two buffers into it's tx fifo where they are
+ * definitely going to be sent on the interface, but the hardware does
+ * not flip the OWN bit on the descriptors until after the buffer has
+ * finished being sent to the CPLD. Therefore, just looking at the own
+ * bit and the buffer pointed to by the dl->head is not enough.
+ *
+ * NOTE: Do not print anything to the console from the time a soft
+ * underrun is detected until the transmit descriptors are fixed up
+ * again. Otherwise the hardware could advance past where you set the
+ * head and tail pointers and then eventually run into the desciptor
+ * that it was currently working on when the softunderrun condition was
+ * first hit. */
+ if (unlikely(vb_is_softunderrun(vb))) {
+ softunderrun = 1;
+ /* If we experienced a soft underrun, the recover function will
+ * a) ensure that all non-idle buffers have been completely
+ * tranmitted by the hardware b) Reset any idle buffers that
+ * have been completely transmitted c) Reset the head and tail
+ * pointers to somwhere in advance of where the hardware is
+ * currently processing and d) return how many idle_buffers were
+ * transmitted before our interrupt handler was called. */
+ idle_buffers = vb_recover_tx_descriptor_list(vb);
+ vb_increase_latency(vb, idle_buffers);
+ } else {
+ softunderrun = 0;
+ idle_buffers = 0;
+ }
+ /* Now we can process the completed non-idle buffers since we know at
+ * this point that the transmit descriptor is in a "good" state. */
+ for (i = 0; i < buffer_count; ++i)
+ handle_transmit(vb, vb->vbb_stash[i]);
+
+ /* If underrun is set, it means that the hardware signalled that it
+ * completely ran out of transmit descriptors. This is what we are
+ * trying to avoid with all this racy softunderun business, but alas,
+ * it's still possible to happen if interrupts are locked longer than
+ * DRING_SIZE milliseconds for some reason. We should have already fixed
+ * up the descriptor ring in this case, so let's just tell the hardware
+ * to reread what it believes the next descriptor is. */
if (unlikely(underrun)) {
+ if (printk_ratelimit()) {
+ dev_info(&vb->pdev->dev, "Host failed to service "
+ "card interrupt within %d ms which is a "
+ "hardunderun.\n", DRING_SIZE);
+ }
vb_rx_demand_poll(vb);
vb_tx_demand_poll(vb);
clear_bit(TX_UNDERRUN, &vb->flags);
}
- while ((vbb = vb_get_completed_rxb(vb))) {
- vb->handle_receive(vbb, vb->context);
- vb_submit_rxb(vb, vbb);
+ /* Print any messages about soft latency bumps after we fix the transmit
+ * descriptor ring. Otherwise it's possible to take so much time
+ * printing the dmesg output that we lose the lead that we got on the
+ * hardware, resulting in a hard underrun condition. */
+ if (unlikely(softunderrun &&
+ !test_bit(LATENCY_LOCKED, &vb->flags) && printk_ratelimit())) {
+ if (vb->max_latency != vb->min_tx_buffer_count) {
+ dev_info(&vb->pdev->dev, "Missed interrupt. "
+ "Increasing latency to %d ms in order to "
+ "compensate.\n", vb->min_tx_buffer_count);
+ } else {
+ dev_info(&vb->pdev->dev, "ERROR: Unable to service "
+ "card within %d ms and unable to further "
+ "increase latency.\n", vb->max_latency);
+ }
}
- stop_vb_deferred(vb);
+ /* And finally, pass up any receive buffers. We also use vb->count to
+ * make a half-hearted attempt to not pass any recieved idle buffers to
+ * the caller, but this needs more work.... */
+ while ((vb->vbb_stash[0] = vb_get_completed_rxb(vb))) {
+ if (vb->count) {
+ vb->handle_receive(vb->vbb_stash[0], vb->context);
+ --vb->count;
+ }
+ vb_submit_rxb(vb, vb->vbb_stash[0]);
+ }
}
-
/*!
* \brief Interrupt handler for VoiceBus interface.
*
@@ -1262,15 +1590,15 @@ vb_isr(int irq, void *dev_id)
}
if (int_status & FATAL_BUS_ERROR_INTERRUPT)
- VB_PRINTK(vb, ERR, "Fatal Bus Error detected!\n");
+ dev_err(&vb->pdev->dev, "Fatal Bus Error detected!\n");
if (int_status & TX_STOPPED_INTERRUPT) {
- assert(test_bit(STOP, &vb->flags));
+ BUG_ON(!test_bit(STOP, &vb->flags));
__vb_disable_interrupts(vb);
complete(&vb->stopped_completion);
}
if (int_status & RX_STOPPED_INTERRUPT) {
- assert(test_bit(STOP, &vb->flags));
+ BUG_ON(!test_bit(STOP, &vb->flags));
if (vb_is_stopped(vb)) {
__vb_disable_interrupts(vb);
complete(&vb->stopped_completion);
@@ -1334,8 +1662,7 @@ vb_tasklet(unsigned long data)
* \todo Complete this description.
*/
int
-voicebus_init(struct pci_dev *pdev, u32 framesize,
- const char *board_name,
+voicebus_init(struct pci_dev *pdev, u32 framesize, const char *board_name,
void (*handle_receive)(void *vbb, void *context),
void (*handle_transmit)(void *vbb, void *context),
void *context,
@@ -1346,11 +1673,11 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
int retval = 0;
struct voicebus *vb;
- assert(NULL != pdev);
- assert(NULL != board_name);
- assert(framesize);
- assert(NULL != handle_receive);
- assert(NULL != handle_transmit);
+ BUG_ON(NULL == pdev);
+ BUG_ON(NULL == board_name);
+ BUG_ON(0 == framesize);
+ BUG_ON(NULL == handle_receive);
+ BUG_ON(NULL == handle_transmit);
/* ----------------------------------------------------------------
Initialize the pure software constructs.
@@ -1358,20 +1685,19 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
*vbp = NULL;
vb = kmalloc(sizeof(*vb), GFP_KERNEL);
if (NULL == vb) {
- VB_PRINTK(vb, DEBUG, "Failed to allocate memory for voicebus "\
- "interface.\n");
+ dev_dbg(&vb->pdev->dev, "Failed to allocate memory for "
+ "voicebus interface.\n");
retval = -ENOMEM;
goto cleanup;
}
memset(vb, 0, sizeof(*vb));
+ vb->pdev = pdev;
+ pci_set_drvdata(pdev, vb);
voicebus_setdebuglevel(vb, debuglevel);
- /* \todo make sure there is a note that the caller needs to make sure
- * board_name stays in memory until voicebus_release is called.
- */
- vb->board_name = board_name;
+ vb->max_latency = VOICEBUS_DEFAULT_MAXLATENCY;
+
spin_lock_init(&vb->lock);
init_completion(&vb->stopped_completion);
- vb->pdev = pdev;
set_bit(STOP, &vb->flags);
clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
vb->framesize = framesize;
@@ -1413,26 +1739,46 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
SLAB_HWCACHE_ALIGN, NULL, NULL);
#endif
#else
+#ifdef DEBUG
+ vb->buffer_cache = kmem_cache_create(board_name, vb->framesize, 0,
+ SLAB_HWCACHE_ALIGN | SLAB_STORE_USER |
+ SLAB_POISON | SLAB_DEBUG_FREE, NULL);
+#else
vb->buffer_cache = kmem_cache_create(board_name, vb->framesize, 0,
SLAB_HWCACHE_ALIGN, NULL);
#endif
+#endif
if (NULL == vb->buffer_cache) {
- VB_PRINTK(vb, ERR, "Failed to allocate buffer cache.\n");
+ dev_err(&vb->pdev->dev, "Failed to allocate buffer cache.\n");
goto cleanup;
}
-
+#ifdef CONFIG_VOICEBUS_SYSFS
+ dev_dbg(&vb->pdev->dev, "Creating sysfs attributes.\n");
+ retval = device_create_file(&vb->pdev->dev,
+ &dev_attr_voicebus_current_latency);
+ if (retval) {
+ dev_dbg(&vb->pdev->dev,
+ "Failed to create device attributes.\n");
+ goto cleanup;
+ }
+#endif
/* ----------------------------------------------------------------
Configure the hardware / kernel module interfaces.
---------------------------------------------------------------- */
+ if (pci_set_dma_mask(vb->pdev, DMA_BIT_MASK(32))) {
+ dev_err(&vb->pdev->dev, "No suitable DMA available.\n");
+ goto cleanup;
+ }
+
if (pci_read_config_byte(vb->pdev, 0x0c, &vb->cache_line_size)) {
- VB_PRINTK(vb, ERR, "Failed read of cache line " \
- "size from PCI configuration space.\n");
+ dev_err(&vb->pdev->dev, "Failed read of cache line "
+ "size from PCI configuration space.\n");
goto cleanup;
}
if (pci_enable_device(pdev)) {
- VB_PRINTK(vb, ERR, "Failed call to pci_enable_device.\n");
+ dev_err(&vb->pdev->dev, "Failed call to pci_enable_device.\n");
retval = -EIO;
goto cleanup;
}
@@ -1440,18 +1786,21 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
/* \todo This driver should be modified to use the memory mapped I/O
as opposed to IO space for portability and performance. */
if (0 == (pci_resource_flags(pdev, 0)&IORESOURCE_IO)) {
- VB_PRINTK(vb, ERR, "BAR0 is not IO Memory.\n");
+ dev_err(&vb->pdev->dev, "BAR0 is not IO Memory.\n");
retval = -EIO;
goto cleanup;
}
vb->iobase = pci_resource_start(pdev, 0);
if (NULL == request_region(vb->iobase, 0xff, board_name)) {
- VB_PRINTK(vb, ERR, "IO Registers are in use by another " \
+ dev_err(&vb->pdev->dev, "IO Registers are in use by another "
"module.\n");
retval = -EIO;
goto cleanup;
}
+ vb->idle_vbb = dma_alloc_coherent(&vb->pdev->dev, vb->framesize,
+ &vb->idle_vbb_dma_addr, GFP_KERNEL);
+
retval = vb_initialize_tx_descriptors(vb);
if (retval)
goto cleanup;
@@ -1463,18 +1812,20 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
/* ----------------------------------------------------------------
Configure the hardware interface.
---------------------------------------------------------------- */
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ release_region(vb->iobase, 0xff);
+ dev_warn(&vb->pdev->dev, "No suitable DMA available.\n");
+ goto cleanup;
+ }
+
pci_set_master(pdev);
vb_enable_io_access(vb);
#if VOICEBUS_DEFERRED != TIMER
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-# define VB_IRQ_SHARED SA_SHIRQ
-#else
-# define VB_IRQ_SHARED IRQF_SHARED
-#endif
- if (request_irq(pdev->irq, vb_isr, VB_IRQ_SHARED, vb->board_name,
- vb)) {
- assert(0);
+ retval = request_irq(pdev->irq, vb_isr, DAHDI_IRQ_SHARED,
+ board_name, vb);
+ if (retval) {
+ dev_warn(&vb->pdev->dev, "Failed to request interrupt line.\n");
goto cleanup;
}
#endif
@@ -1501,6 +1852,9 @@ cleanup:
if (vb->rxd.desc)
vb_free_descriptors(vb, &vb->rxd);
+ dma_free_coherent(&vb->pdev->dev, vb->framesize,
+ vb->idle_vbb, vb->idle_vbb_dma_addr);
+
if (vb->buffer_cache)
kmem_cache_destroy(vb->buffer_cache);
@@ -1511,7 +1865,7 @@ cleanup:
pci_disable_device(vb->pdev);
kfree(vb);
- assert(0 != retval);
+ WARN_ON(0 == retval);
return retval;
}
EXPORT_SYMBOL(voicebus_init);
@@ -1525,6 +1879,12 @@ voicebus_get_pci_dev(struct voicebus *vb)
}
EXPORT_SYMBOL(voicebus_get_pci_dev);
+void *voicebus_pci_dev_to_context(struct pci_dev *pdev)
+{
+ return ((struct voicebus *)pci_get_drvdata(pdev))->context;
+}
+EXPORT_SYMBOL(voicebus_pci_dev_to_context);
+
static spinlock_t loader_list_lock;
static struct list_head binary_loader_list;
@@ -1560,12 +1920,14 @@ int vpmadtreg_loadfirmware(struct voicebus *vb)
module_put(loader->owner);
} else {
spin_unlock(&loader_list_lock);
- printk(KERN_INFO "Failed to find a registered loader after loading module.\n");
+ dev_info(&vb->pdev->dev, "Failed to find a "
+ "registered loader after loading module.\n");
ret = -ENODEV;
}
} else {
spin_unlock(&loader_list_lock);
- printk(KERN_INFO "Failed to find a registered loader after loading module.\n");
+ dev_info(&vb->pdev->dev, "Failed to find a registered "
+ "loader after loading module.\n");
ret = -1;
}
return ret;
diff --git a/drivers/dahdi/voicebus/voicebus.h b/drivers/dahdi/voicebus/voicebus.h
index eaa51e6..16768df 100644
--- a/drivers/dahdi/voicebus/voicebus.h
+++ b/drivers/dahdi/voicebus/voicebus.h
@@ -32,10 +32,13 @@
struct voicebus;
#define VOICEBUS_DEFAULT_LATENCY 3
+#define VOICEBUS_DEFAULT_MAXLATENCY 25
+#define VOICEBUS_MAXLATENCY_BUMP 6
void voicebus_setdebuglevel(struct voicebus *vb, u32 level);
int voicebus_getdebuglevel(struct voicebus *vb);
-struct pci_dev * voicebus_get_pci_dev(struct voicebus *vb);
+struct pci_dev *voicebus_get_pci_dev(struct voicebus *vb);
+void *voicebus_pci_dev_to_context(struct pci_dev *pdev);
int voicebus_init(struct pci_dev* pdev, u32 framesize,
const char *board_name,
void (*handle_receive)(void *buffer, void *context),
@@ -52,10 +55,13 @@ void voicebus_set_handlers(struct voicebus *vb,
void voicebus_release(struct voicebus *vb);
int voicebus_start(struct voicebus *vb);
int voicebus_stop(struct voicebus *vb);
-void * voicebus_alloc(struct voicebus* vb);
+void *voicebus_alloc(struct voicebus* vb);
void voicebus_free(struct voicebus *vb, void *vbb);
int voicebus_transmit(struct voicebus *vb, void *vbb);
int voicebus_set_minlatency(struct voicebus *vb, unsigned int milliseconds);
-int voicebus_current_latency(struct voicebus *vb) ;
+int voicebus_current_latency(struct voicebus *vb);
+void voicebus_lock_latency(struct voicebus *vb);
+void voicebus_unlock_latency(struct voicebus *vb);
+int voicebus_is_latency_locked(const struct voicebus *vb);
#endif /* __VOICEBUS_H__ */
diff --git a/drivers/dahdi/wcb4xxp/base.c b/drivers/dahdi/wcb4xxp/base.c
index 1e05309..965eed9 100644
--- a/drivers/dahdi/wcb4xxp/base.c
+++ b/drivers/dahdi/wcb4xxp/base.c
@@ -47,6 +47,15 @@
#include "wcb4xxp.h"
+#ifndef BIT /* added in 2.6.24 */
+#define BIT(i) (1UL << (i))
+#endif
+#define BIT_SET(x, i) ((x) |= BIT(i))
+#define BIT_CLR(x, i) ((x) &= ~BIT(i))
+#define IS_SET(x, i) (((x) & BIT(i)) != 0)
+#define BITMASK(i) (((u64)1 << (i)) - 1)
+
+
#if (DAHDI_CHUNKSIZE != 8)
#error Sorry, wcb4xxp does not support chunksize != 8
#endif
@@ -72,10 +81,10 @@
#define DBG_HDLC (debug & DEBUG_HDLC)
#define DBG_ALARM (debug & DEBUG_ALARM)
-#define DBG_SPANFILTER ((1 << bspan->port) & spanfilter)
+#define DBG_SPANFILTER (BIT(bspan->port) & spanfilter)
static int debug = 0;
-static int spanfilter = 15;
+static int spanfilter = 0xFF; /* Bitmap for ports 1-8 */
#ifdef LOOPBACK_SUPPORTED
static int loopback = 0;
#endif
@@ -114,9 +123,22 @@ static struct proc_dir_entry *myproc;
struct devtype {
char *desc;
unsigned int flags;
+ int ports; /* Number of ports the card has */
+ enum cards_ids card_type; /* Card type - Digium B410P, ... */
};
-static struct devtype wcb4xxp = { "Wildcard B410P", 0 };
+static struct devtype wcb4xxp = {"Wildcard B410P", .ports = 4, .card_type = B410P };
+static struct devtype hfc2s = {"HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .card_type = DUOBRI };
+static struct devtype hfc4s = {"HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .card_type = QUADBRI };
+static struct devtype hfc8s = {"HFC-4S Junghanns.NET octoBRI PCI", .ports = 8, .card_type = OCTOBRI };
+static struct devtype hfc2s_OV = {"OpenVox B200P", .ports = 2, .card_type = B200P_OV };
+static struct devtype hfc4s_OV = {"OpenVox B400P", .ports = 4, .card_type = B400P_OV };
+static struct devtype hfc8s_OV = {"OpenVox B800P", .ports = 8, .card_type = B800P_OV };
+static struct devtype hfc2s_BN = {"BeroNet BN2S0", .ports = 2, .card_type = BN2S0 };
+static struct devtype hfc4s_BN = {"BeroNet BN4S0", .ports = 4, .card_type = BN4S0 };
+static struct devtype hfc8s_BN = {"BeroNet BN8S0", .ports = 8, .card_type = BN8S0 };
+
+#define CARD_HAS_EC(card) ((card)->card_type == B410P)
static int echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec);
@@ -403,7 +425,18 @@ static void hfc_gpio_init(struct b4xxp *b4)
mb();
- b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0); /* GPIO0..7 S/T, 8..15 GPIO */
+ switch (b4->card_type) {
+ case OCTOBRI: /* fall through */
+ case B800P_OV: /* fall through */
+ case BN8S0:
+ /* GPIO0..15 S/T - HFC-8S uses GPIO8-15 for S/T ports 5-8 */
+ b4xxp_setreg8(b4, R_GPIO_SEL, 0x00);
+ break;
+ default:
+ /* GPIO0..7 S/T, 8..15 GPIO */
+ b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0);
+ break;
+ }
mb();
@@ -618,13 +651,16 @@ static void ec_init(struct b4xxp *b4)
unsigned char b;
unsigned int i, j, mask;
+ if (!CARD_HAS_EC(b4))
+ return;
+
/* Setup GPIO */
for (i=0; i < NUM_EC; i++) {
b = ec_read(b4, i, 0x1a0);
dev_info(b4->dev, "VPM %d/%d init: chip ver %02x\n", i, NUM_EC - 1, b);
- for (j=0; j < 4; j++) {
+ for (j=0; j < b4->numspans; j++) {
ec_write(b4, i, 0x1a8 + j, 0x00); /* GPIO out */
ec_write(b4, i, 0x1ac + j, 0x00); /* GPIO dir */
ec_write(b4, i, 0x1b0 + j, 0x00); /* GPIO sel */
@@ -1008,7 +1044,18 @@ static void hfc_assign_dchan_fifo(struct b4xxp *b4, int port)
int fifo, hfc_chan;
unsigned long irq_flags;
- fifo = port + 8;
+ switch (b4->card_type) {
+ case B800P_OV: /* fall through */
+ case OCTOBRI: /* fall through */
+ case BN8S0:
+ /* In HFC-8S cards we can't use ports 8-11 for dchan FIFOs */
+ fifo = port + 16;
+ break;
+ default:
+ fifo = port + 8;
+ break;
+ }
+
hfc_chan = (port * 4) + 2;
/* record the host's FIFO # in the span fifo array */
@@ -1210,7 +1257,7 @@ static void hfc_update_st_timers(struct b4xxp *b4)
int i, j;
struct b4xxp_span *s;
- for (i=0; i < 4; i++) {
+ for (i=0; i < b4->numspans; i++) {
s = &b4->spans[i];
for (j=HFC_T1; j <= HFC_T3; j++) {
@@ -1413,12 +1460,21 @@ static void hfc_init_all_st(struct b4xxp *b4)
gpio = b4xxp_getreg8(b4, R_GPI_IN3);
- for (i=0; i < 4; i++) {
+ for (i=0; i < b4->numspans; i++) {
s = &b4->spans[i];
s->parent = b4;
s->port = i;
- nt = ((gpio & (1 << (i + 4))) == 0); /* GPIO=0 = NT mode */
+ /* The way the Digium B410P card reads the NT/TE mode
+ * jumper is the oposite of how other HFC-4S cards do:
+ * - In B410P: GPIO=0: NT
+ * - In Junghanns: GPIO=0: TE
+ */
+ if (b4->card_type == B410P)
+ nt = ((gpio & (1 << (i + 4))) == 0);
+ else
+ nt = ((gpio & (1 << (i + 4))) != 0);
+
s->te_mode = !nt;
dev_info(b4->dev, "Port %d: %s mode\n", i + 1, (nt ? "NT" : "TE"));
@@ -1774,9 +1830,15 @@ static void b4xxp_init_stage1(struct b4xxp *b4)
/*
* set up the clock controller
- * we have a 24.576MHz crystal, so the PCM clock is 2x the incoming clock.
+ * B410P has a 24.576MHz crystal, so the PCM clock is 2x the incoming clock.
+ * Other cards have a 49.152Mhz crystal, so the PCM clock equals incoming clock.
*/
- b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02);
+
+ if (b4->card_type == B410P)
+ b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02);
+ else
+ b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK);
+
flush_pci();
udelay(100); /* wait a bit for clock to settle */
@@ -1807,7 +1869,7 @@ static void b4xxp_init_stage2(struct b4xxp *b4)
/*
* set up the flow controller.
- * B channel map:
+ * B channel map: (4 ports cards with Hardware Echo Cancel present & active)
* FIFO 0 connects Port 1 B0 using HFC channel 16 and PCM timeslots 0/1.
* FIFO 1 connects Port 1 B1 using HFC channel 17 and PCM timeslots 4/5.
* FIFO 2 connects Port 2 B0 using HFC channel 20 and PCM timeslots 8/9.
@@ -1822,14 +1884,35 @@ static void b4xxp_init_stage2(struct b4xxp *b4)
*
* D channels are handled by FIFOs 8-11.
* FIFO 8 connects Port 1 D using HFC channel 3
- * FIFO 9 connects Port 1 D using HFC channel 7
- * FIFO 10 connects Port 1 D using HFC channel 11
- * FIFO 11 connects Port 1 D using HFC channel 15
+ * FIFO 9 connects Port 2 D using HFC channel 7
+ * FIFO 10 connects Port 3 D using HFC channel 11
+ * FIFO 11 connects Port 4 D using HFC channel 15
*
* D channel FIFOs are operated in HDLC mode and interrupt on end of frame.
+ *
+ * B channel map: (8 ports cards without Hardware Echo Cancel)
+ * FIFO 0 connects Port 1 B0 using HFC channel 0
+ * FIFO 1 connects Port 1 B1 using HFC channel 1
+ * FIFO 2 connects Port 2 B0 using HFC channel 4
+ * FIFO 3 connects Port 2 B1 using HFC channel 5
+ * .........................
+ * FIFO 14 connects Port 8 B0 using HFC channel 28
+ * FIFO 15 connects Port 8 B1 using HFC channel 29
+ *
+ * All B channel FIFOs have their HDLC controller in transparent mode,
+ * and only the FIFO for B0 on each port has its interrupt operational.
+ *
+ * D channels are handled by FIFOs 16-23.
+ * FIFO 16 connects Port 1 D using HFC channel 3
+ * FIFO 17 connects Port 2 D using HFC channel 7
+ * FIFO 18 connects Port 3 D using HFC channel 11
+ * FIFO 19 connects Port 4 D using HFC channel 15
+ * ................
+ * FIFO 23 connects Port 8 D using HFC channel 31
+ * D channel FIFOs are operated in HDLC mode and interrupt on end of frame.
*/
for (span=0; span < b4->numspans; span++) {
- if (vpmsupport) {
+ if ((vpmsupport) && (CARD_HAS_EC(b4))) {
hfc_assign_bchan_fifo_ec(b4, span, 0);
hfc_assign_bchan_fifo_ec(b4, span, 1);
} else {
@@ -1854,6 +1937,79 @@ static void b4xxp_setleds(struct b4xxp *b4, unsigned char val)
ec_write(b4, 0, 0x1a8 + 3, val);
}
+static void b4xxp_update_leds_hfc_8s(struct b4xxp *b4)
+{
+ unsigned long lled = 0; /* A bit set is a led OFF */
+ unsigned long leddw;
+ int j;
+ struct b4xxp_span *bspan;
+
+ b4->blinktimer++;
+ for (j = 7; j >= 0; j--) {
+ bspan = &b4->spans[7 - j];
+ if (!(bspan->span.flags & DAHDI_FLAG_RUNNING) ||
+ bspan->span.alarms) {
+ BIT_SET(lled, j);
+ continue; /* Led OFF */
+ }
+
+ if (bspan->span.mainttimer || bspan->span.maintstat) {
+ /* Led Blinking in maint state */
+ if (b4->blinktimer >= 0x7f)
+ BIT_SET(lled, j);
+ }
+ /* Else: Led on */
+ }
+
+ /* Write Leds...*/
+ leddw = lled << 24 | lled << 16 | lled << 8 | lled;
+ b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x21);
+ iowrite16(0x4000, b4->ioaddr + 4);
+ iowrite32(leddw, b4->ioaddr);
+ b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x20);
+
+ if (b4->blinktimer == 0xff)
+ b4->blinktimer = -1;
+}
+
+/* So far only tested for OpenVox cards. Please test it for other hardware */
+static void b4xxp_update_leds_hfc(struct b4xxp *b4)
+{
+ int i;
+ int leds = 0, green_leds = 0; /* Default: off */
+ struct b4xxp_span *bspan;
+
+ b4->blinktimer++;
+ for (i=0; i < b4->numspans; i++) {
+ bspan = &b4->spans[i];
+
+ if (!(bspan->span.flags & DAHDI_FLAG_RUNNING))
+ continue; /* Leds are off */
+
+ if (bspan->span.alarms) {
+ /* Red blinking -> Alarm */
+ if (b4->blinktimer >= 0x7f)
+ BIT_SET(leds, i);
+ } else if (bspan->span.mainttimer || bspan->span.maintstat) {
+ /* Green blinking -> Maint status */
+ if (b4->blinktimer >= 0x7f)
+ BIT_SET(green_leds, i);
+ } else {
+ /* Steady grean -> No Alarm */
+ BIT_SET(green_leds, i);
+ }
+ }
+
+ /* Actually set them. for red: just set the bit in R_GPIO_EN1.
+ For green: in both R_GPIO_EN1 and R_GPIO_OUT1. */
+ leds |= green_leds;
+ b4xxp_setreg8(b4, R_GPIO_EN1, leds);
+ b4xxp_setreg8(b4, R_GPIO_OUT1, green_leds);
+
+ if (b4->blinktimer == 0xff)
+ b4->blinktimer = -1;
+}
+
static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val)
{
int shift, spanmask;
@@ -1871,6 +2027,18 @@ static void b4xxp_update_leds(struct b4xxp *b4)
int i;
struct b4xxp_span *bspan;
+ if (b4->numspans == 8) {
+ /* Use the alternative function for non-Digium HFC-8S cards */
+ b4xxp_update_leds_hfc_8s(b4);
+ return;
+ }
+
+ if (b4->card_type != B410P) {
+ /* Use the alternative function for non-Digium HFC-4S cards */
+ b4xxp_update_leds_hfc(b4);
+ return;
+ }
+
b4->blinktimer++;
for (i=0; i < b4->numspans; i++) {
bspan = &b4->spans[i];
@@ -2174,7 +2342,7 @@ static void init_spans(struct b4xxp *b4)
bspan->span.close = b4xxp_close;
bspan->span.ioctl = b4xxp_ioctl;
bspan->span.hdlc_hard_xmit = b4xxp_hdlc_hard_xmit;
- if (vpmsupport)
+ if (vpmsupport && CARD_HAS_EC(b4))
bspan->span.echocan_create = echocan_create;
/* HDLC stuff */
@@ -2281,13 +2449,21 @@ DAHDI_IRQ_HANDLER(b4xxp_interrupt)
static void b4xxp_bottom_half(unsigned long data)
{
struct b4xxp *b4 = (struct b4xxp *)data;
- int i, j, k, gotrxfifo, fifo;
+ int i, j, k, gotrxfifo, fifo, fifo_low, fifo_high;
unsigned char b, b2;
if (b4->shutdown)
return;
gotrxfifo = 0;
+ /* HFC-4S d-chan fifos 8-11 *** HFC-8S d-chan fifos 16-23 */
+ if (b4->numspans == 8) {
+ fifo_low = 16;
+ fifo_high = 23;
+ } else {
+ fifo_low = 8;
+ fifo_high = 11;
+ }
for (i=0; i < 8; i++) {
b = b2 = b4->fifo_irqstatus[i];
@@ -2296,7 +2472,8 @@ static void b4xxp_bottom_half(unsigned long data)
fifo = i*4 + j;
if (b & V_IRQ_FIFOx_TX) {
- if (fifo >=8 && fifo <= 11) { /* d-chan fifo */
+ if (fifo >= fifo_low && fifo <= fifo_high) {
+ /* d-chan fifos */
/*
* WOW I don't like this.
* It's bad enough that I have to send a fake frame to get an HDLC TX FIFO interrupt,
@@ -2305,7 +2482,7 @@ static void b4xxp_bottom_half(unsigned long data)
* Yuck. It works well, but yuck.
*/
do {
- k = hdlc_tx_frame(&b4->spans[fifo - 8]);
+ k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]);
} while (k);
} else {
if (printk_ratelimit())
@@ -2314,7 +2491,7 @@ static void b4xxp_bottom_half(unsigned long data)
}
if (b & V_IRQ_FIFOx_RX) {
- if (fifo >=8 && fifo <= 11) {
+ if (fifo >= fifo_low && fifo <= fifo_high) { /* dchan fifos */
/*
* I have to loop here until hdlc_rx_frame says there are no more frames waiting.
* for whatever reason, the HFC will not generate another interrupt if there are
@@ -2322,7 +2499,7 @@ static void b4xxp_bottom_half(unsigned long data)
* i.e. I get an int when F1 changes, not when F1 != F2.
*/
do {
- k = hdlc_rx_frame(&b4->spans[fifo - 8]);
+ k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]);
} while (k);
} else {
if (printk_ratelimit())
@@ -2404,8 +2581,8 @@ static int b4xxp_proc_read_one(char *buf, struct b4xxp *b4)
sprintf(sBuf, "Card %d, PCI identifier %s, IRQ %d\n", b4->cardno + 1, b4->dev->bus_id, b4->irq);
strcat(sBuf,"Tx:\n");
- for (j=0; j<8; j++) {
- for (i=0; i<12; i++) {
+ for (j=0; j<(b4->numspans * 2) ; j++) { /* B Channels */
+ for (i=0; i<(b4->numspans * 3) ; i++) { /* All Channels */
chan = b4->spans[i/3].chans[i%3];
sprintf(str, "%02x ", chan->writechunk[j]);
strcat(sBuf, str);
@@ -2415,8 +2592,8 @@ static int b4xxp_proc_read_one(char *buf, struct b4xxp *b4)
}
strcat(sBuf, "\nRx:\n");
- for (j=0; j < 8; j++) {
- for (i=0; i < 12; i++) {
+ for (j=0; j < (b4->numspans * 2); j++) { /* B Channels */
+ for (i=0; i < (b4->numspans * 3); i++) { /* All Channels */
chan = b4->spans[i / 3].chans[i % 3];
sprintf(str, "%02x%c", chan->readchunk[j], (i == 11) ? '\n' : ' ');
strcat(sBuf, str);
@@ -2424,7 +2601,7 @@ static int b4xxp_proc_read_one(char *buf, struct b4xxp *b4)
}
strcat(sBuf, "\nPort states:\n");
- for (i=0; i < 4; i++) {
+ for (i=0; i < b4->numspans; i++) {
int state;
char *x;
struct b4xxp_span *s = &b4->spans[i];
@@ -2524,7 +2701,7 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
/* card found, enabled and main struct allocated. Fill it out. */
b4->magic = WCB4XXP_MAGIC;
b4->variety = dt->desc;
-
+ b4->card_type = dt->card_type;
b4->pdev = pdev;
b4->dev = &pdev->dev;
pci_set_drvdata(pdev, b4);
@@ -2538,7 +2715,7 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
spin_lock_init(&b4->fifolock);
x = b4xxp_getreg8(b4, R_CHIP_ID);
- if (x != 0xc0) { /* wrong chip? */
+ if ((x != 0xc0) && (x != 0x80)) { /* wrong chip? */
dev_err(&pdev->dev, "Unknown/unsupported controller detected (R_CHIP_ID = 0x%02x)\n", x);
goto err_out_free_mem;
}
@@ -2553,7 +2730,7 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
*/
/* TODO: determine whether this is a 2, 4 or 8 port card */
- b4->numspans = 4;
+ b4->numspans = dt->ports;
b4->syncspan = -1; /* sync span is unknown */
if (b4->numspans > MAX_SPANS_PER_CARD) {
dev_err(b4->dev, "Driver does not know how to handle a %d span card!\n", b4->numspans);
@@ -2706,7 +2883,17 @@ static void __devexit b4xxp_remove(struct pci_dev *pdev)
static struct pci_device_id b4xx_ids[] __devinitdata =
{
{ 0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb4xxp },
- { 0, }
+ { 0x1397, 0x16b8, 0x1397, 0xe552, 0, 0, (unsigned long)&hfc8s },
+ { 0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s },
+ { 0x1397, 0x08b4, 0x1397, 0xb556, 0, 0, (unsigned long)&hfc2s },
+ { 0x1397, 0x08b4, 0x1397, 0xe884, 0, 0, (unsigned long)&hfc2s_OV },
+ { 0x1397, 0x08b4, 0x1397, 0xe888, 0, 0, (unsigned long)&hfc4s_OV },
+ { 0x1397, 0x16b8, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV },
+ { 0x1397, 0x08b4, 0x1397, 0xb566, 0, 0, (unsigned long)&hfc2s_BN },
+ { 0x1397, 0x08b4, 0x1397, 0xb560, 0, 0, (unsigned long)&hfc4s_BN },
+ { 0x1397, 0x16b8, 0x1397, 0xb562, 0, 0, (unsigned long)&hfc8s_BN },
+ {0, }
+
};
static struct pci_driver b4xx_driver = {
@@ -2766,7 +2953,7 @@ MODULE_PARM_DESC(timer_1_ms, "NT: msec to wait for link activation, TE: unused."
MODULE_PARM_DESC(timer_3_ms, "TE: msec to wait for link activation, NT: unused.");
MODULE_AUTHOR("Digium Incorporated <support@digium.com>");
-MODULE_DESCRIPTION("B410P quad-port BRI module driver.");
+MODULE_DESCRIPTION("B410P & Similars multi-port BRI module driver.");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, b4xx_ids);
diff --git a/drivers/dahdi/wcb4xxp/wcb4xxp.h b/drivers/dahdi/wcb4xxp/wcb4xxp.h
index 4542a2d..2807349 100644
--- a/drivers/dahdi/wcb4xxp/wcb4xxp.h
+++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h
@@ -378,7 +378,7 @@
#define HFC_T3 2
#define WCB4XXP_MAGIC 0xb410c0de
-#define MAX_SPANS_PER_CARD 4
+#define MAX_SPANS_PER_CARD 8
#define WCB4XXP_CHANNELS_PER_SPAN 3 /* 2 B-channels and 1 D-Channel for each BRI span */
#define WCB4XXP_HDLC_BUF_LEN 32 /* arbitrary, just the max # of byts we will send to DAHDI per call */
@@ -415,6 +415,19 @@ struct b4xxp_span {
struct dahdi_chan _chans[WCB4XXP_CHANNELS_PER_SPAN]; /* Backing memory */
};
+enum cards_ids { /* Cards ==> Brand & Model */
+ B410P = 0, /* Digium B410P */
+ B200P_OV, /* OpenVox B200P */
+ B400P_OV, /* OpenVox B400P */
+ B800P_OV, /* OpenVox B800P */
+ DUOBRI, /* HFC-2S Junghanns.NET duoBRI PCI */
+ QUADBRI, /* HFC-4S Junghanns.NET quadBRI PCI */
+ OCTOBRI, /* HFC-8S Junghanns.NET octoBRI PCI */
+ BN2S0, /* BeroNet BN2S0 */
+ BN4S0, /* Beronet BN4S0 */
+ BN8S0 /* BeroNet BN8S0 */
+ };
+
/* This structure exists one per card */
struct b4xxp {
unsigned magic; /* magic value to make sure we're looking at our struct */
@@ -453,6 +466,7 @@ struct b4xxp {
struct b4xxp_span spans[MAX_SPANS_PER_CARD]; /* Individual spans */
int order; /* Order */
int flags; /* Device flags */
+ enum cards_ids card_type; /* For LED handling mostly */
int master; /* Are we master */
int ledreg; /* copy of the LED Register */
unsigned int gpio;
diff --git a/drivers/dahdi/wcfxo.c b/drivers/dahdi/wcfxo.c
index 7f8a210..d5bb658 100644
--- a/drivers/dahdi/wcfxo.c
+++ b/drivers/dahdi/wcfxo.c
@@ -673,6 +673,16 @@ static int wcfxo_hardware_init(struct wcfxo *wc)
/* Hardware stuff */
/* Reset PCI Interface chip and registers */
outb(0x0e, wc->ioaddr + WC_CNTL);
+
+ /* Set all to outputs except AUX 4, which is an input */
+ outb(0xef, wc->ioaddr + WC_AUXC);
+
+ /* Reset the DAA (DAA uses AUX5 for reset) */
+ outb(0x00, wc->ioaddr + WC_AUXD);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1 + HZ / 800);
+
+ /* Set hook state to on hook & un-reset the DAA */
if (wc->flags & FLAG_RESET_ON_AUX5) {
/* Set hook state to on hook for when we switch.
Make sure reset is high */
@@ -681,8 +691,6 @@ static int wcfxo_hardware_init(struct wcfxo *wc)
/* Set hook state to on hook for when we switch */
outb(0x24, wc->ioaddr + WC_AUXD);
}
- /* Set all to outputs except AUX 4, which is an input */
- outb(0xef, wc->ioaddr + WC_AUXC);
/* Back to normal, with automatic DMA wrap around */
outb(0x01, wc->ioaddr + WC_CNTL);
diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
index 63a3bfc..acbdd73 100644
--- a/drivers/dahdi/wct4xxp/base.c
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -167,7 +167,10 @@ static int t1e1override = -1; //0xFF; // -1 = jumper; 0xFF = E1
static int j1mode = 0;
static int sigmode = FRMR_MODE_NO_ADDR_CMP;
static int loopback = 0;
-static int alarmdebounce = 0;
+static int alarmdebounce = 2500; /* LOF/LFA def to 2.5s AT&T TR54016*/
+static int losalarmdebounce = 2500;/* LOS def to 2.5s AT&T TR54016*/
+static int aisalarmdebounce = 2500;/* AIS(blue) def to 2.5s AT&T TR54016*/
+static int yelalarmdebounce = 500;/* RAI(yellow) def to 0.5s AT&T devguide */
#ifdef VPM_SUPPORT
static int vpmsupport = 1;
/* If set to auto, vpmdtmfsupport is enabled for VPM400M and disabled for VPM450M */
@@ -250,6 +253,9 @@ struct t4_span {
int redalarms;
int notclear;
int alarmcount;
+ int losalarmcount;
+ int aisalarmcount;
+ int yelalarmcount;
int spanflags;
int syncpos;
#ifdef SUPPORT_GEN1
@@ -1913,7 +1919,7 @@ static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlev
else
mytxlevel = txlevel - 4;
fmr1 = 0x9c; /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */
- fmr2 = 0x22; /* FMR2: no payload loopback, auto send yellow alarm */
+ fmr2 = 0x20; /* FMR2: no payload loopback, don't auto yellow */
if (loopback)
fmr2 |= 0x4;
fmr4 = 0x0c; /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */
@@ -2555,15 +2561,51 @@ static void t4_check_alarms(struct t4 *wc, int span)
alarms |= DAHDI_ALARM_NOTOPEN;
}
- if (c & 0xa0) {
- if (ts->alarmcount >= alarmdebounce)
+ if (c & 0x20) { /* LOF/LFA */
+ if (ts->alarmcount >= alarmdebounce)
alarms |= DAHDI_ALARM_RED;
- else
+ else {
+ if (unlikely(debug && !ts->alarmcount)) {
+ /* starting to debounce LOF/LFA */
+ printk(KERN_INFO "wct%dxxp: LOF/LFA detected "
+ "on span %d but debouncing for %d ms\n",
+ wc->numspans, span + 1, alarmdebounce);
+ }
ts->alarmcount++;
+ }
} else
ts->alarmcount = 0;
- if (c & 0x4)
- alarms |= DAHDI_ALARM_BLUE;
+
+ if (c & 0x80) { /* LOS */
+ if (ts->losalarmcount >= losalarmdebounce)
+ alarms |= DAHDI_ALARM_RED;
+ else {
+ if (unlikely(debug && !ts->losalarmcount)) {
+ /* starting to debounce LOS */
+ printk(KERN_INFO "wct%dxxp: LOS detected on "
+ "span %d but debouncing for %d ms\n",
+ wc->numspans, span + 1, losalarmdebounce);
+ }
+ ts->losalarmcount++;
+ }
+ } else
+ ts->losalarmcount = 0;
+
+ if (c & 0x40) { /* AIS */
+ if (ts->aisalarmcount >= aisalarmdebounce)
+ alarms |= DAHDI_ALARM_BLUE;
+ else {
+ if (unlikely(debug && !ts->aisalarmcount)) {
+ /* starting to debounce AIS */
+ printk(KERN_INFO "wct%dxxp: AIS detected on "
+ "span %d but debouncing for %d ms\n",
+ wc->numspans, span + 1, aisalarmdebounce);
+ }
+ ts->aisalarmcount++;
+ }
+ } else
+ ts->aisalarmcount = 0;
+
if (((!ts->span.alarms) && alarms) ||
(ts->span.alarms && (!alarms)))
@@ -2579,7 +2621,8 @@ static void t4_check_alarms(struct t4 *wc, int span)
if (alarms && !(ts->spanflags & FLAG_SENDINGYELLOW)) {
unsigned char fmr4;
#if 1
- printk(KERN_INFO "wct%dxxp: Setting yellow alarm on span %d\n", wc->numspans, span + 1);
+ printk(KERN_INFO "wct%dxxp: Setting yellow alarm on span %d\n",
+ wc->numspans, span + 1);
#endif
/* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
fmr4 = __t4_framer_in(wc, span, 0x20);
@@ -2588,7 +2631,8 @@ static void t4_check_alarms(struct t4 *wc, int span)
} else if ((!alarms) && (ts->spanflags & FLAG_SENDINGYELLOW)) {
unsigned char fmr4;
#if 1
- printk(KERN_INFO "wct%dxxp: Clearing yellow alarm on span %d\n", wc->numspans, span + 1);
+ printk(KERN_INFO "wct%dxxp: Clearing yellow alarm on span %d\n",
+ wc->numspans, span + 1);
#endif
/* We manually do yellow alarm to handle RECOVER */
fmr4 = __t4_framer_in(wc, span, 0x20);
@@ -2598,8 +2642,23 @@ static void t4_check_alarms(struct t4 *wc, int span)
/* Re-check the timing source when we enter/leave alarm, not withstanding
yellow alarm */
- if (c & 0x10)
- alarms |= DAHDI_ALARM_YELLOW;
+ if (c & 0x10) { /* receiving yellow (RAI) */
+ if (ts->yelalarmcount >= yelalarmdebounce)
+ alarms |= DAHDI_ALARM_YELLOW;
+ else {
+ if (unlikely(debug && !ts->yelalarmcount)) {
+ /* starting to debounce AIS */
+ printk(KERN_INFO "wct%dxxp: yelllow (RAI) "
+ "detected on span %d but debouncing "
+ "for %d ms\n",
+ wc->numspans, span + 1,
+ yelalarmdebounce);
+ }
+ ts->yelalarmcount++;
+ }
+ } else
+ ts->yelalarmcount = 0;
+
if (ts->span.mainttimer || ts->span.maintstat)
alarms |= DAHDI_ALARM_LOOPBACK;
ts->span.alarms = alarms;
@@ -2615,8 +2674,11 @@ static void t4_do_counters(struct t4 *wc)
int docheck=0;
spin_lock(&wc->reglock);
- if (ts->loopupcnt || ts->loopdowncnt)
+ if (ts->loopupcnt || ts->loopdowncnt || ts->alarmcount
+ || ts->losalarmcount || ts->aisalarmcount
+ || ts->yelalarmcount)
docheck++;
+
if (ts->alarmtimer) {
if (!--ts->alarmtimer) {
docheck++;
@@ -2639,7 +2701,7 @@ static inline void __handle_leds(struct t4 *wc)
for (x=0;x<wc->numspans;x++) {
struct t4_span *ts = wc->tspans[x];
if (ts->span.flags & DAHDI_FLAG_RUNNING) {
- if (ts->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) {
+ if ((ts->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) || ts->losalarmcount) {
#ifdef FANCY_ALARM
if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
__t4_set_led(wc, x, WC_RED);
@@ -3814,6 +3876,7 @@ static void __devexit t4_remove_one(struct pci_dev *pdev)
{
struct t4 *wc = pci_get_drvdata(pdev);
struct dahdi_span *span;
+ int basesize;
int i;
if (!wc) {
@@ -3829,6 +3892,10 @@ static void __devexit t4_remove_one(struct pci_dev *pdev)
wc->vpm450m = NULL;
/* Unregister spans */
+ basesize = DAHDI_MAX_CHUNKSIZE * 32 * 4;
+ if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN))
+ basesize = basesize * 2;
+
for (i = 0; i < wc->numspans; ++i) {
span = &wc->tspans[i]->span;
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags))
@@ -3849,7 +3916,9 @@ static void __devexit t4_remove_one(struct pci_dev *pdev)
pci_release_regions(pdev);
/* Immediately free resources */
- pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma);
+
+ pci_free_consistent(pdev, basesize * 2,
+ (void *)wc->writechunk, wc->writedma);
order_index[wc->order]--;
@@ -3931,6 +4000,9 @@ module_param(noburst, int, 0600);
module_param(timingcable, int, 0600);
module_param(t1e1override, int, 0600);
module_param(alarmdebounce, int, 0600);
+module_param(losalarmdebounce, int, 0600);
+module_param(aisalarmdebounce, int, 0600);
+module_param(yelalarmdebounce, int, 0600);
module_param(j1mode, int, 0600);
module_param(sigmode, int, 0600);
#ifdef VPM_SUPPORT
diff --git a/drivers/dahdi/wct4xxp/wct4xxp-diag.c b/drivers/dahdi/wct4xxp/wct4xxp-diag.c
index 9e81c23..6554193 100644
--- a/drivers/dahdi/wct4xxp/wct4xxp-diag.c
+++ b/drivers/dahdi/wct4xxp/wct4xxp-diag.c
@@ -393,7 +393,7 @@ int main(int argc, char *argv[])
if (*(argv[1]) == '/')
dahdi_copy_string(fn, argv[1], sizeof(fn));
else
- snprintf(fn, sizeof(fn), "/dev/zap/%d", atoi(argv[1]));
+ snprintf(fn, sizeof(fn), "/dev/dahdi/%d", atoi(argv[1]));
fd = open(fn, O_RDWR);
if (fd <0) {
fprintf(stderr, "Unable to open '%s': %s\n", fn, strerror(errno));
diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index b3e3f07..7cbea1d 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -3400,19 +3400,16 @@ wctc4xxp_add_to_device_list(struct wcdte *wc)
struct wctc4xxp_desc {
const char *short_name;
const char *long_name;
- int flags;
};
static struct wctc4xxp_desc wctc400p = {
.short_name = "tc400b",
.long_name = "Wildcard TC400P+TC400M",
- .flags = 0,
};
static struct wctc4xxp_desc wctce400 = {
.short_name = "tce400",
.long_name = "Wildcard TCE400+TC400M",
- .flags = 0,
};
static int __devinit
@@ -3475,7 +3472,7 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
init_waitqueue_head(&wc->waitq);
- if (pci_set_dma_mask(wc->pdev, DMA_32BIT_MASK)) {
+ if (pci_set_dma_mask(wc->pdev, DMA_BIT_MASK(32))) {
release_region(wc->iobase, 0xff);
DTE_PRINTK(WARNING, "No suitable DMA available.\n");
return -EIO;
diff --git a/drivers/dahdi/wctdm.c b/drivers/dahdi/wctdm.c
index 84f074f..eb0516a 100644
--- a/drivers/dahdi/wctdm.c
+++ b/drivers/dahdi/wctdm.c
@@ -441,10 +441,14 @@ static void wctdm_restart_dma(struct wctdm *wc);
static inline void __write_8bits(struct wctdm *wc, unsigned char bits)
{
- /* Drop chip select */
+/* Out BIT_CS --\________________________________/---- */
+/* Out BIT_SCLK ---\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/------ */
+/* Out BIT_SDI ---\___/---\___/---\___/---\___/-------- */
+/* Data Bit 7 6 5 4 3 2 1 0 */
+/* Data written 0 1 0 1 0 1 0 1 */
+
int x;
- wc->ios |= BIT_SCLK;
- outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Drop chip select */
wc->ios &= ~BIT_CS;
outb(wc->ios, wc->ioaddr + WC_AUXD);
for (x=0;x<8;x++) {
@@ -455,6 +459,7 @@ static inline void __write_8bits(struct wctdm *wc, unsigned char bits)
wc->ios &= ~BIT_SDI;
wc->ios &= ~BIT_SCLK;
outb(wc->ios, wc->ioaddr + WC_AUXD);
+
/* Now raise SCLK high again and repeat */
wc->ios |= BIT_SCLK;
outb(wc->ios, wc->ioaddr + WC_AUXD);
@@ -463,7 +468,6 @@ static inline void __write_8bits(struct wctdm *wc, unsigned char bits)
/* Finally raise CS back high again */
wc->ios |= BIT_CS;
outb(wc->ios, wc->ioaddr + WC_AUXD);
-
}
static inline void __reset_spi(struct wctdm *wc)
@@ -493,31 +497,36 @@ static inline void __reset_spi(struct wctdm *wc)
static inline unsigned char __read_8bits(struct wctdm *wc)
{
+/* Out BIT_CS --\________________________________________/----*/
+/* Out BIT_SCLK ---\_/--\_/--\_/--\_/--\_/--\_/--\_/--\_/-------*/
+/* In BIT_SDO ????/1111\0000/1111\0000/1111\0000/1111\0000/???*/
+/* Data bit 7 6 5 4 3 2 1 0 */
+/* Data Read 1 0 1 0 1 0 1 0 */
+
+/* Note: Clock High time is 2x Low time, due to input read */
+
unsigned char res=0, c;
int x;
- wc->ios |= BIT_SCLK;
- outb(wc->ios, wc->ioaddr + WC_AUXD);
/* Drop chip select */
wc->ios &= ~BIT_CS;
outb(wc->ios, wc->ioaddr + WC_AUXD);
for (x=0;x<8;x++) {
res <<= 1;
- /* Get SCLK */
+ /* Drop SCLK */
wc->ios &= ~BIT_SCLK;
outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Now raise SCLK high again */
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+
/* Read back the value */
c = inb(wc->ioaddr + WC_AUXR);
if (c & BIT_SDO)
res |= 1;
- /* Now raise SCLK high again */
- wc->ios |= BIT_SCLK;
- outb(wc->ios, wc->ioaddr + WC_AUXD);
}
/* Finally raise CS back high again */
wc->ios |= BIT_CS;
outb(wc->ios, wc->ioaddr + WC_AUXD);
- wc->ios &= ~BIT_SCLK;
- outb(wc->ios, wc->ioaddr + WC_AUXD);
/* And return our result */
return res;
@@ -727,22 +736,23 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
{
+ struct fxs *const fxs = &wc->mod[card].fxs;
int res;
/* Check loopback */
res = wc->reg1shadow[card];
- if (!res && (res != wc->mod[card].fxs.lasttxhook)) {
+ if (!res && (res != fxs->lasttxhook)) {
res = wctdm_getreg(wc, card, 8);
if (res) {
printk(KERN_NOTICE "Ouch, part reset, quickly restoring reality (%d)\n", card);
wctdm_init_proslic(wc, card, 1, 0, 1);
} else {
- if (wc->mod[card].fxs.palarms++ < MAX_ALARMS) {
+ if (fxs->palarms++ < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1);
- if (wc->mod[card].fxs.lasttxhook == 4)
- wc->mod[card].fxs.lasttxhook = 1;
- wctdm_setreg(wc, card, 64, wc->mod[card].fxs.lasttxhook);
+ if (fxs->lasttxhook == SLIC_LF_RINGING)
+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD;
+ wctdm_setreg(wc, card, 64, fxs->lasttxhook);
} else {
- if (wc->mod[card].fxs.palarms == MAX_ALARMS)
+ if (fxs->palarms == MAX_ALARMS)
printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1);
}
}
@@ -842,6 +852,21 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
}
}
+ if (unlikely(DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig)) {
+ /*
+ * dahdi-base will set DAHDI_RXSIG_INITIAL after a
+ * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events
+ * will be queued on the channel with the current received
+ * hook state. Channels that use robbed-bit signalling always
+ * report the current received state via the dahdi_rbsbits
+ * call. Since we only call dahdi_hooksig when we've detected
+ * a change to report, let's forget our current state in order
+ * to force us to report it again via dahdi_hooksig.
+ *
+ */
+ fxo->battery = BATTERY_UNKNOWN;
+ }
+
if (abs(b) < battthresh) {
/* possible existing states:
battery lost, no debounce timer
@@ -966,6 +991,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
{
+ struct fxs *const fxs = &wc->mod[card].fxs;
char res;
int hook;
@@ -974,47 +1000,63 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
res = wc->reg0shadow[card];
hook = (res & 1);
- if (hook != wc->mod[card].fxs.lastrxhook) {
+ if (hook != fxs->lastrxhook) {
/* Reset the debounce (must be multiple of 4ms) */
- wc->mod[card].fxs.debounce = 8 * (4 * 8);
+ fxs->debounce = 8 * (4 * 8);
#if 0
- printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod[card].fxs.debounce);
+ printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n",
+ card, hook, fxs->debounce);
#endif
} else {
- if (wc->mod[card].fxs.debounce > 0) {
- wc->mod[card].fxs.debounce-= 16 * DAHDI_CHUNKSIZE;
+ if (fxs->debounce > 0) {
+ fxs->debounce -= 16 * DAHDI_CHUNKSIZE;
#if 0
- printk(KERN_DEBUG "Sustaining hook %d, %d\n", hook, wc->mod[card].fxs.debounce);
+ printk(KERN_DEBUG "Sustaining hook %d, %d\n",
+ hook, fxs->debounce);
#endif
- if (!wc->mod[card].fxs.debounce) {
+ if (!fxs->debounce) {
#if 0
printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook);
#endif
- wc->mod[card].fxs.debouncehook = hook;
+ fxs->debouncehook = hook;
}
- if (!wc->mod[card].fxs.oldrxhook && wc->mod[card].fxs.debouncehook) {
+ if (!fxs->oldrxhook && fxs->debouncehook) {
/* Off hook */
#if 1
if (debug)
#endif
printk(KERN_DEBUG "wctdm: Card %d Going off hook\n", card);
+
+ switch (fxs->lasttxhook) {
+ case SLIC_LF_RINGING:
+ case SLIC_LF_OHTRAN_FWD:
+ case SLIC_LF_OHTRAN_REV:
+ /* just detected OffHook, during
+ * Ringing or OnHookTransfer */
+ fxs->idletxhookstate =
+ POLARITY_XOR(card) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+ break;
+ }
+
dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
if (robust)
wctdm_init_proslic(wc, card, 1, 0, 1);
- wc->mod[card].fxs.oldrxhook = 1;
+ fxs->oldrxhook = 1;
- } else if (wc->mod[card].fxs.oldrxhook && !wc->mod[card].fxs.debouncehook) {
+ } else if (fxs->oldrxhook && !fxs->debouncehook) {
/* On hook */
#if 1
if (debug)
#endif
printk(KERN_DEBUG "wctdm: Card %d Going on hook\n", card);
dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK);
- wc->mod[card].fxs.oldrxhook = 0;
+ fxs->oldrxhook = 0;
}
}
}
- wc->mod[card].fxs.lastrxhook = hook;
+ fxs->lastrxhook = hook;
}
DAHDI_IRQ_HANDLER(wctdm_interrupt)
@@ -1046,27 +1088,40 @@ DAHDI_IRQ_HANDLER(wctdm_interrupt)
for (x=0;x<4;x++) {
if (wc->cardflag & (1 << x) &&
(wc->modtype[x] == MOD_TYPE_FXS)) {
- if (wc->mod[x].fxs.lasttxhook == 0x4) {
+ struct fxs *const fxs = &wc->mod[x].fxs;
+ if (fxs->lasttxhook == SLIC_LF_RINGING) {
/* RINGing, prepare for OHT */
- wc->mod[x].fxs.ohttimer = OHT_TIMER << 3;
+ fxs->ohttimer = OHT_TIMER << 3;
/* logical XOR 3 variables
module parameter 'reversepolarity', global reverse all FXS lines.
ioctl channel variable fxs 'reversepolarity', Line Reversal Alert Signal if required.
ioctl channel variable fxs 'vmwi_lrev', VMWI pending.
*/
- wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x6 : 0x2;/* OHT mode when idle */
- } else {
- if (wc->mod[x].fxs.ohttimer) {
- wc->mod[x].fxs.ohttimer-= DAHDI_CHUNKSIZE;
- if (!wc->mod[x].fxs.ohttimer) {
- wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to Active : Reverse Forward */
- if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook == 0x6)) {
- /* Apply the change if appropriate */
- wc->mod[x].fxs.lasttxhook = POLARITY_XOR(x) ? 0x5 : 0x1;
- wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook);
- }
- }
+
+ /* OHT mode when idle */
+ fxs->idletxhookstate = POLARITY_XOR(x) ?
+ SLIC_LF_OHTRAN_REV :
+ SLIC_LF_OHTRAN_FWD;
+ } else if (fxs->ohttimer) {
+ fxs->ohttimer -= DAHDI_CHUNKSIZE;
+ if (fxs->ohttimer)
+ continue;
+
+ /* Switch to Active : Reverse Forward */
+ fxs->idletxhookstate = POLARITY_XOR(x) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+
+ if ((fxs->lasttxhook == SLIC_LF_OHTRAN_FWD) ||
+ (fxs->lasttxhook == SLIC_LF_OHTRAN_REV)) {
+ /* Apply the change if appropriate */
+ fxs->lasttxhook = POLARITY_XOR(x) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+
+ wctdm_setreg(wc, x, 64,
+ fxs->lasttxhook);
}
}
}
@@ -1454,6 +1509,7 @@ static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx)
static int set_vmwi(struct wctdm * wc, int chan_idx)
{
+ struct fxs *const fxs = &wc->mod[chan_idx].fxs;
if (wc->mod[chan_idx].fxs.vmwi_active_messages){
wc->mod[chan_idx].fxs.vmwi_lrev = (wc->mod[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_LREV)?1:0;
wc->mod[chan_idx].fxs.vmwi_hvdc = (wc->mod[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_HVDC)?1:0;
@@ -1474,21 +1530,21 @@ static int set_vmwi(struct wctdm * wc, int chan_idx)
);
}
if (POLARITY_XOR(chan_idx)) {
- wc->mod[chan_idx].fxs.idletxhookstate |= 0x4;
+ wc->mod[chan_idx].fxs.idletxhookstate |= SLIC_LF_REVMASK;
/* Do not set while currently ringing or open */
- if (wc->mod[chan_idx].fxs.lasttxhook != 0x04 &&
- wc->mod[chan_idx ].fxs.lasttxhook != 0x00) {
- wc->mod[chan_idx ].fxs.lasttxhook |= 0x4;
- wctdm_setreg(wc, chan_idx, 64, wc->mod[chan_idx].fxs.lasttxhook);
- }
+ if ((fxs->lasttxhook != SLIC_LF_RINGING) &&
+ (fxs->lasttxhook != SLIC_LF_OPEN)) {
+ fxs->lasttxhook |= SLIC_LF_REVMASK;
+ wctdm_setreg(wc, chan_idx, 64, fxs->lasttxhook);
+ }
} else {
- wc->mod[chan_idx].fxs.idletxhookstate &= ~0x04;
+ wc->mod[chan_idx].fxs.idletxhookstate &= ~SLIC_LF_REVMASK;
/* Do not set while currently ringing or open */
- if (wc->mod[chan_idx].fxs.lasttxhook != 0x04 &&
- wc->mod[chan_idx].fxs.lasttxhook != 0x00) {
- wc->mod[chan_idx].fxs.lasttxhook &= ~0x04;
+ if ((fxs->lasttxhook != SLIC_LF_RINGING) &&
+ (fxs->lasttxhook != SLIC_LF_OPEN)) {
+ wc->mod[chan_idx].fxs.lasttxhook &= ~SLIC_LF_REVMASK;
wctdm_setreg(wc, chan_idx, 64, wc->mod[chan_idx].fxs.lasttxhook);
- }
+ }
}
return 0;
}
@@ -1619,9 +1675,9 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
/* By default, don't send on hook */
if (!reversepolarity != !wc->mod[card].fxs.reversepolarity)
- wc->mod[card].fxs.idletxhookstate = 5;
+ wc->mod[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_REV;
else
- wc->mod[card].fxs.idletxhookstate = 1;
+ wc->mod[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_FWD;
if (sane) {
/* Make sure we turn off the DC->DC converter to prevent anything from blowing up */
@@ -1850,6 +1906,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
struct wctdm_echo_coefs echoregs;
struct dahdi_hwgain hwgain;
struct wctdm *wc = chan->pvt;
+ struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs;
int x;
switch (cmd) {
case DAHDI_ONHOOKTRANSFER:
@@ -1858,10 +1915,18 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
if (get_user(x, (__user int *) data))
return -EFAULT;
wc->mod[chan->chanpos - 1].fxs.ohttimer = x << 3;
- wc->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; /* OHT mode when idle */
- if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) {
+
+ /* Active mode when idle */
+ fxs->idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+
+ if ((fxs->lasttxhook == SLIC_LF_ACTIVE_FWD) ||
+ (fxs->lasttxhook == SLIC_LF_ACTIVE_REV)) {
/* Apply the change if appropriate */
- wc->mod[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2;
+ fxs->lasttxhook = POLARITY_XOR(chan->chanpos - 1) ?
+ SLIC_LF_OHTRAN_REV :
+ SLIC_LF_OHTRAN_FWD;
wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
}
break;
@@ -1871,15 +1936,15 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
return -EINVAL;
/* Can't change polarity while ringing or when open */
- if ((wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) ||
- (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00))
+ if ((fxs->lasttxhook == SLIC_LF_RINGING) ||
+ (fxs->lasttxhook == SLIC_LF_OPEN))
return -EINVAL;
wc->mod[chan->chanpos - 1].fxs.reversepolarity = x;
if ( POLARITY_XOR(chan->chanpos - 1) )
- wc->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04;
+ fxs->lasttxhook |= SLIC_LF_REVMASK;
else
- wc->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04;
+ fxs->lasttxhook &= ~SLIC_LF_REVMASK;
wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
break;
case DAHDI_VMWI_CONFIG:
@@ -2010,7 +2075,11 @@ static int wctdm_close(struct dahdi_chan *chan)
wc->usecount--;
module_put(THIS_MODULE);
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
- wc->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x5 : 0x1;
+ int idlehookstate;
+ idlehookstate = POLARITY_XOR(chan->chanpos - 1) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = idlehookstate;
}
/* If we're dead, release us now */
if (!wc->usecount && wc->dead)
@@ -2038,45 +2107,51 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
printk(KERN_NOTICE "wcfxo: Can't set tx state to %d\n", txsig);
}
} else {
+ struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs;
switch(txsig) {
case DAHDI_TXSIG_ONHOOK:
switch(chan->sig) {
case DAHDI_SIG_FXOKS:
case DAHDI_SIG_FXOLS:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = (wc->mod[chan->chanpos-1].fxs.vmwi_hvac ? 4 : wc->mod[chan->chanpos-1].fxs.idletxhookstate);
+ fxs->lasttxhook = fxs->vmwi_hvac ?
+ SLIC_LF_RINGING :
+ fxs->idletxhookstate;
break;
case DAHDI_SIG_EM:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
+ fxs->lasttxhook = fxs->idletxhookstate;
break;
case DAHDI_SIG_FXOGS:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = 3;
+ fxs->lasttxhook = SLIC_LF_TIP_OPEN;
break;
}
break;
case DAHDI_TXSIG_OFFHOOK:
switch(chan->sig) {
case DAHDI_SIG_EM:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = 5;
+ fxs->lasttxhook = SLIC_LF_ACTIVE_REV;
break;
default:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
+ fxs->lasttxhook = fxs->idletxhookstate;
break;
}
break;
case DAHDI_TXSIG_START:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = 4;
+ fxs->lasttxhook = SLIC_LF_RINGING;
break;
case DAHDI_TXSIG_KEWL:
- wc->mod[chan->chanpos-1].fxs.lasttxhook = 0;
+ fxs->lasttxhook = SLIC_LF_OPEN;
break;
default:
printk(KERN_NOTICE "wctdm: Can't set tx state to %d\n", txsig);
}
- if (debug)
- printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, wc->mod[chan->chanpos-1].fxs.lasttxhook);
+ if (debug) {
+ printk(KERN_DEBUG
+ "Setting FXS hook state to %d (%02x)\n",
+ txsig, fxs->lasttxhook);
+ }
#if 1
- wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos-1].fxs.lasttxhook);
+ wctdm_setreg(wc, chan->chanpos - 1, 64, fxs->lasttxhook);
#endif
}
return 0;
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 7f68473..1386e5f 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -162,17 +162,17 @@ static int ectrans[4] = { 0, 1, 3, 2 };
#include "fxo_modes.h"
struct wctdm_desc {
- char *name;
- int flags;
- int ports;
+ const char *name;
+ const int flags;
+ const int ports;
};
-static struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 };
-static struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 };
-static struct wctdm_desc wctdm410 = { "Wildcard TDM410P", 0, 4 };
-static struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", FLAG_EXPRESS, 24 };
-static struct wctdm_desc wcaex800 = { "Wildcard AEX800", FLAG_EXPRESS, 8 };
-static struct wctdm_desc wcaex410 = { "Wildcard AEX410", FLAG_EXPRESS, 4 };
+static const struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 };
+static const struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 };
+static const struct wctdm_desc wctdm410 = { "Wildcard TDM410P", 0, 4 };
+static const struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", FLAG_EXPRESS, 24 };
+static const struct wctdm_desc wcaex800 = { "Wildcard AEX800", FLAG_EXPRESS, 8 };
+static const struct wctdm_desc wcaex410 = { "Wildcard AEX410", FLAG_EXPRESS, 4 };
static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 };
@@ -462,9 +462,8 @@ static int config_vpmadt032(struct vpmadt032 *vpm)
}
-static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writechunk, int whichframe)
+static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, u8 *writechunk, int whichframe)
{
- unsigned long flags;
struct vpmadt032_cmd *curcmd = NULL;
struct vpmadt032 *vpmadt032 = wc->vpmadt032;
int x;
@@ -473,8 +472,6 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec
/* Skip audio */
writechunk += 24;
- spin_lock_irqsave(&wc->reglock, flags);
-
if (test_bit(VPM150M_SPIRESET, &vpmadt032->control) || test_bit(VPM150M_HPIRESET, &vpmadt032->control)) {
if (debug & DEBUG_ECHOCAN)
printk(KERN_INFO "HW Resetting VPMADT032...\n");
@@ -489,7 +486,6 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec
writechunk[CMD_BYTE(x, 1, 0)] = 0;
writechunk[CMD_BYTE(x, 2, 0)] = 0x00;
}
- spin_unlock_irqrestore(&wc->reglock, flags);
return;
}
@@ -548,7 +544,6 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec
writechunk[CMD_BYTE(27, 2, 0)] = 0;
}
} else if (test_and_clear_bit(VPM150M_SWRESET, &vpmadt032->control)) {
- printk(KERN_INFO "Booting VPMADT032\n");
for (x = 24; x < 28; x++) {
if (x == 24)
writechunk[CMD_BYTE(x, 0, 0)] = (0x8 << 4);
@@ -577,11 +572,9 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec
if (test_bit(VPM150M_ACTIVE, &vpmadt032->control) && !whichframe && !(wc->intcount % 100)) {
schedule_work(&vpmadt032->work);
}
-
- spin_unlock_irqrestore(&wc->reglock, flags);
}
-static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writechunk, int card, int pos)
+static inline void cmd_dequeue(struct wctdm *wc, unsigned char *writechunk, int card, int pos)
{
unsigned long flags;
unsigned int curcmd=0;
@@ -624,7 +617,7 @@ static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writech
if (!curcmd) {
/* If nothing else, use filler */
if (wc->modtype[card] == MOD_TYPE_FXS)
- curcmd = CMD_RD(64);
+ curcmd = CMD_RD(LINE_STATE);
else if (wc->modtype[card] == MOD_TYPE_FXO)
curcmd = CMD_RD(12);
else if (wc->modtype[card] == MOD_TYPE_QRV)
@@ -752,7 +745,7 @@ static inline void cmd_decipher_vpmadt032(struct wctdm *wc, unsigned char *readc
#endif
}
-static inline void cmd_decipher(struct wctdm *wc, volatile unsigned char *readchunk, int card)
+static inline void cmd_decipher(struct wctdm *wc, u8 *readchunk, int card)
{
unsigned long flags;
unsigned char ident;
@@ -819,7 +812,7 @@ static inline void cmd_checkisr(struct wctdm *wc, int card)
#ifdef PAQ_DEBUG
wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(19); /* Transistor interrupts */
#else
- wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(64); /* Battery mode */
+ wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(LINE_STATE);
#endif
} else if (wc->modtype[card] == MOD_TYPE_FXO) {
wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(29); /* Battery */
@@ -850,7 +843,7 @@ static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechun
}
if (likely(wc->initialized)) {
- if (y < wc->type)
+ if (y < wc->desc->ports)
writechunk[y] = wc->chans[y]->writechunk[x];
}
cmd_dequeue(wc, writechunk, y, x);
@@ -878,7 +871,7 @@ static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechun
writechunk[EFRAME_SIZE] = wc->ctlreg;
writechunk[EFRAME_SIZE + 1] = wc->txident++;
- if ((wc->type == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_CARDS] == MOD_TYPE_NONE))) {
+ if ((wc->desc->ports == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_CARDS] == MOD_TYPE_NONE))) {
writechunk[EFRAME_SIZE + 2] = 0;
for (y = 0; y < 4; y++) {
if (wc->modtype[y] == MOD_TYPE_NONE)
@@ -1032,11 +1025,8 @@ static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk)
}
}
for (y=0;y < wc->cards;y++) {
- if (likely(wc->initialized)) {
- if (y < wc->type) {
- wc->chans[y]->readchunk[x] = readchunk[y];
- }
- }
+ if (likely(wc->initialized) && (y < wc->desc->ports))
+ wc->chans[y]->readchunk[x] = readchunk[y];
cmd_decipher(wc, readchunk, y);
}
if (wc->vpm100) {
@@ -1050,7 +1040,7 @@ static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk)
}
/* XXX We're wasting 8 taps. We should get closer :( */
if (likely(wc->initialized)) {
- for (x=0;x<wc->type;x++) {
+ for (x = 0; x < wc->desc->ports; x++) {
if (wc->cardflag & (1 << x))
dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->chans[x]->writechunk);
}
@@ -1088,7 +1078,7 @@ static int wait_access(struct wctdm *wc, int card)
static unsigned char translate_3215(unsigned char address)
{
int x;
- for (x=0;x<sizeof(indirect_regs)/sizeof(indirect_regs[0]);x++) {
+ for (x = 0; x < ARRAY_SIZE(indirect_regs); x++) {
if (indirect_regs[x].address == address) {
address = indirect_regs[x].altaddr;
break;
@@ -1145,7 +1135,7 @@ static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card)
{
unsigned char i;
- for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(indirect_regs); i++)
{
if(wctdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial))
return -1;
@@ -1160,7 +1150,7 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
unsigned short i, initial;
int j;
- for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(indirect_regs); i++)
{
if((j = wctdm_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) {
printk(KERN_NOTICE "Failed to read indirect register %d\n", i);
@@ -1188,56 +1178,55 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
{
+ struct fxs *const fxs = &wc->mods[card].fxs;
int res;
+ unsigned long flags;
#ifdef PAQ_DEBUG
res = wc->cmdq[card].isrshadow[1];
res &= ~0x3;
if (res) {
wc->cmdq[card].isrshadow[1]=0;
- wc->mods[card].fxs.palarms++;
- if (wc->mods[card].fxs.palarms < MAX_ALARMS) {
+ fxs->palarms++;
+ if (fxs->palarms < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm (%02x) on module %d, resetting!\n", res, card + 1);
- if (wc->mods[card].fxs.lasttxhook == 4) {
- wc->mods[card].fxs.lasttxhook = POLARITY_XOR(card) ? 0x15 : 0x11;
- }
wc->sethook[card] = CMD_WR(19, res);
-#if 0
- wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook);
-#endif
-
- /* wctdm_setreg_intr(wc, card, 64, wc->mods[card].fxs.lasttxhook); */
/* Update shadow register to avoid extra power alarms until next read */
wc->cmdq[card].isrshadow[1] = 0;
} else {
- if (wc->mods[card].fxs.palarms == MAX_ALARMS)
+ if (fxs->palarms == MAX_ALARMS)
printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1);
}
}
#else
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
res = wc->cmdq[card].isrshadow[1];
/* This makes sure the lasthook was put in reg 64 the linefeed reg */
- if (((res & 0x0f) | 0x10) == wc->mods[card].fxs.lasttxhook)
- wc->mods[card].fxs.lasttxhook &= 0x0f;
+ if (((res & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING) == fxs->lasttxhook)
+ fxs->lasttxhook &= SLIC_LF_SETMASK;
res = !res && /* reg 64 has to be zero at last isr read */
- !(wc->mods[card].fxs.lasttxhook & 0x10 ) && /* not a transition */
- wc->mods[card].fxs.lasttxhook; /* not an intended zero */
+ !(fxs->lasttxhook & SLIC_LF_OPPENDING) && /* not a transition */
+ fxs->lasttxhook; /* not an intended zero */
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
if (res) {
- wc->mods[card].fxs.palarms++;
- if (wc->mods[card].fxs.palarms < MAX_ALARMS) {
+ fxs->palarms++;
+ if (fxs->palarms < MAX_ALARMS) {
printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1);
- if (wc->mods[card].fxs.lasttxhook == 4) {
- wc->mods[card].fxs.lasttxhook = POLARITY_XOR(card) ? 0x15 : 0x11;;
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
+ if (fxs->lasttxhook == SLIC_LF_RINGING) {
+ fxs->lasttxhook = POLARITY_XOR(card) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;;
}
- wc->mods[card].fxs.lasttxhook |= 0x10;
- wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook);
+ fxs->lasttxhook |= SLIC_LF_OPPENDING;
+ wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
- /* wctdm_setreg_intr(wc, card, 64, wc->mods[card].fxs.lasttxhook); */
/* Update shadow register to avoid extra power alarms until next read */
- wc->cmdq[card].isrshadow[1] = wc->mods[card].fxs.lasttxhook;
+ wc->cmdq[card].isrshadow[1] = fxs->lasttxhook;
} else {
- if (wc->mods[card].fxs.palarms == MAX_ALARMS)
+ if (fxs->palarms == MAX_ALARMS)
printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1);
}
}
@@ -1404,6 +1393,21 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
}
}
+ if (unlikely(DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig)) {
+ /*
+ * dahdi-base will set DAHDI_RXSIG_INITIAL after a
+ * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events
+ * will be queued on the channel with the current received
+ * hook state. Channels that use robbed-bit signalling always
+ * report the current received state via the dahdi_rbsbits
+ * call. Since we only call dahdi_hooksig when we've detected
+ * a change to report, let's forget our current state in order
+ * to force us to report it again via dahdi_hooksig.
+ *
+ */
+ fxo->battery = BATTERY_UNKNOWN;
+ }
+
if (abs_voltage < battthresh) {
/* possible existing states:
battery lost, no debounce timer
@@ -1568,8 +1572,40 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
#undef MS_PER_CHECK_HOOK
}
-static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
+static void wctdm_fxs_off_hook(struct wctdm *wc, const int card)
+{
+ struct fxs *const fxs = &wc->mods[card].fxs;
+
+ if (debug & DEBUG_CARD)
+ printk(KERN_DEBUG "wctdm: Card %d Going off hook\n", card);
+ switch (fxs->lasttxhook) {
+ case SLIC_LF_RINGING: /* Ringing */
+ case SLIC_LF_OHTRAN_FWD: /* Forward On Hook Transfer */
+ case SLIC_LF_OHTRAN_REV: /* Reverse On Hook Transfer */
+ /* just detected OffHook, during Ringing or OnHookTransfer */
+ fxs->idletxhookstate = POLARITY_XOR(card) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+ break;
+ }
+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
+ if (robust)
+ wctdm_init_proslic(wc, card, 1, 0, 1);
+ fxs->oldrxhook = 1;
+}
+
+static void wctdm_fxs_on_hook(struct wctdm *wc, const int card)
+{
+ struct fxs *const fxs = &wc->mods[card].fxs;
+ if (debug & DEBUG_CARD)
+ printk(KERN_DEBUG "wctdm: Card %d Going on hook\n", card);
+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK);
+ fxs->oldrxhook = 0;
+}
+
+static inline void wctdm_proslic_check_hook(struct wctdm *wc, const int card)
{
+ struct fxs *const fxs = &wc->mods[card].fxs;
char res;
int hook;
@@ -1579,46 +1615,36 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
res = wc->cmdq[card].isrshadow[0]; /* Hook state */
hook = (res & 1);
- if (hook != wc->mods[card].fxs.lastrxhook) {
+ if (hook != fxs->lastrxhook) {
/* Reset the debounce (must be multiple of 4ms) */
- wc->mods[card].fxs.debounce = 8 * (4 * 8);
+ fxs->debounce = 8 * (4 * 8);
#if 0
- printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", card, hook, wc->mods[card].fxs.debounce);
+ printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n",
+ card, hook, fxs->debounce);
#endif
} else {
- if (wc->mods[card].fxs.debounce > 0) {
- wc->mods[card].fxs.debounce-= 4 * DAHDI_CHUNKSIZE;
+ if (fxs->debounce > 0) {
+ fxs->debounce -= 4 * DAHDI_CHUNKSIZE;
#if 0
- printk(KERN_DEBUG "Sustaining hook %d, %d\n", hook, wc->mods[card].fxs.debounce);
+ printk(KERN_DEBUG "Sustaining hook %d, %d\n",
+ hook, fxs->debounce);
#endif
- if (!wc->mods[card].fxs.debounce) {
+ if (!fxs->debounce) {
#if 0
printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook);
#endif
- wc->mods[card].fxs.debouncehook = hook;
- }
- if (!wc->mods[card].fxs.oldrxhook && wc->mods[card].fxs.debouncehook) {
- /* Off hook */
- if (debug & DEBUG_CARD)
- printk(KERN_DEBUG "wctdm: Card %d Going off hook\n", card);
- dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
- if (robust)
- wctdm_init_proslic(wc, card, 1, 0, 1);
- wc->mods[card].fxs.oldrxhook = 1;
-
- } else if (wc->mods[card].fxs.oldrxhook && !wc->mods[card].fxs.debouncehook) {
- /* On hook */
- if (debug & DEBUG_CARD)
- printk(KERN_DEBUG "wctdm: Card %d Going on hook\n", card);
- dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK);
- wc->mods[card].fxs.oldrxhook = 0;
+ fxs->debouncehook = hook;
}
+
+ if (!fxs->oldrxhook && fxs->debouncehook)
+ wctdm_fxs_off_hook(wc, card);
+ else if (fxs->oldrxhook && !fxs->debouncehook)
+ wctdm_fxs_on_hook(wc, card);
}
}
- wc->mods[card].fxs.lastrxhook = hook;
+ fxs->lastrxhook = hook;
}
-
static inline void wctdm_vpm_check(struct wctdm *wc, int x)
{
if (wc->cmdq[x].isrshadow[0]) {
@@ -1706,7 +1732,50 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec
unit, channel);
wctdm_vpm_out(wc, unit, channel, 0x01);
} else if (wc->vpmadt032) {
- vpmadt032_echocan_free(wc->vpmadt032, chan, ec);
+ vpmadt032_echocan_free(wc->vpmadt032, chan->chanpos - 1, ec);
+ }
+}
+
+static void wctdm_isr_misc_fxs(struct wctdm *wc, int card)
+{
+ struct fxs *const fxs = &wc->mods[card].fxs;
+ unsigned long flags;
+
+ if (!(wc->intcount % 10000)) {
+ /* Accept an alarm once per 10 seconds */
+ if (fxs->palarms)
+ fxs->palarms--;
+ }
+ wctdm_proslic_check_hook(wc, card);
+ if (!(wc->intcount & 0xfc))
+ wctdm_proslic_recheck_sanity(wc, card);
+ if (SLIC_LF_RINGING == fxs->lasttxhook) {
+ /* RINGing, prepare for OHT */
+ fxs->ohttimer = OHT_TIMER << 3;
+ /* OHT mode when idle */
+ fxs->idletxhookstate = POLARITY_XOR(card) ? SLIC_LF_OHTRAN_REV :
+ SLIC_LF_OHTRAN_FWD;
+ } else if (fxs->ohttimer) {
+ fxs->ohttimer -= DAHDI_CHUNKSIZE;
+ if (fxs->ohttimer)
+ return;
+
+ /* Switch to active */
+ fxs->idletxhookstate = POLARITY_XOR(card) ? SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
+ if (SLIC_LF_OHTRAN_FWD == fxs->lasttxhook) {
+ /* Apply the change if appropriate */
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_FWD;
+ /* Data enqueued here */
+ wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ } else if (SLIC_LF_OHTRAN_REV == fxs->lasttxhook) {
+ /* Apply the change if appropriate */
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_REV;
+ /* Data enqueued here */
+ wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ }
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
}
}
@@ -1721,37 +1790,7 @@ static inline void wctdm_isr_misc(struct wctdm *wc)
for (x=0;x<wc->cards;x++) {
if (wc->cardflag & (1 << x)) {
if (wc->modtype[x] == MOD_TYPE_FXS) {
- if (!(wc->intcount % 10000)) {
- /* Accept an alarm once per 10 seconds */
- if (wc->mods[x].fxs.palarms)
- wc->mods[x].fxs.palarms--;
- }
- wctdm_proslic_check_hook(wc, x);
- if (!(wc->intcount & 0xfc))
- wctdm_proslic_recheck_sanity(wc, x);
- if (wc->mods[x].fxs.lasttxhook == 0x4) {
- /* RINGing, prepare for OHT */
- wc->mods[x].fxs.ohttimer = OHT_TIMER << 3;
- wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x6 : 0x2; /* OHT mode when idle */
- } else {
- if (wc->mods[x].fxs.ohttimer) {
- wc->mods[x].fxs.ohttimer-= DAHDI_CHUNKSIZE;
- if (!wc->mods[x].fxs.ohttimer) {
- wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to active */
- if (wc->mods[x].fxs.lasttxhook == 0x2) {
- /* Apply the change if appropriate */
- wc->mods[x].fxs.lasttxhook = 0x11;
- wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */
- /* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */
- } else if (wc->mods[x].fxs.lasttxhook == 0x6) {
- /* Apply the change if appropriate */
- wc->mods[x].fxs.lasttxhook = 0x15;
- wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */
- /* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */
- }
- }
- }
- }
+ wctdm_isr_misc_fxs(wc, x);
} else if (wc->modtype[x] == MOD_TYPE_FXO) {
wctdm_voicedaa_check_hook(wc, x);
} else if (wc->modtype[x] == MOD_TYPE_QRV) {
@@ -1867,7 +1906,7 @@ static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card)
unsigned char vbat;
/* Turn off linefeed */
- wctdm_setreg(wc, card, 64, 0);
+ wctdm_setreg(wc, card, LINE_STATE, 0);
/* Power down */
wctdm_setreg(wc, card, 14, 0x10);
@@ -2119,42 +2158,68 @@ static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx)
return 0;
}
+static int set_lasttxhook_interruptible(struct fxs *fxs, unsigned newval, int * psethook)
+{
+ int res = 0;
+ unsigned long flags;
+ int timeout = 0;
+
+ do {
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
+ if (SLIC_LF_OPPENDING & fxs->lasttxhook) {
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
+ if (timeout++ > 100)
+ return -1;
+ msleep(1);
+ } else {
+ fxs->lasttxhook = (newval & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING;
+ *psethook = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
+ break;
+ }
+ } while (1);
+
+ return res;
+}
+
+/* Must be called from within an interruptible context */
static int set_vmwi(struct wctdm *wc, int chan_idx)
{
int x;
+ struct fxs *const fxs = &wc->mods[chan_idx].fxs;
+
/* Presently only supports line reversal MWI */
- if (wc->mods[chan_idx].fxs.vmwi_active_messages && wc->mods[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_LREV){
- wc->mods[chan_idx].fxs.vmwi_linereverse = 1;
- } else {
- wc->mods[chan_idx].fxs.vmwi_linereverse = 0;
- }
+ if ((fxs->vmwi_active_messages) &&
+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV))
+ fxs->vmwi_linereverse = 1;
+ else
+ fxs->vmwi_linereverse = 0;
+
/* Set line polarity for new VMWI state */
if (POLARITY_XOR(chan_idx)) {
- wc->mods[chan_idx].fxs.idletxhookstate |= 0x14;
+ fxs->idletxhookstate |= SLIC_LF_OPPENDING | SLIC_LF_REVMASK;
/* Do not set while currently ringing or open */
- if (wc->mods[chan_idx].fxs.lasttxhook != 0x04 &&
- wc->mods[chan_idx].fxs.lasttxhook != 0x00) {
- wc->mods[chan_idx].fxs.lasttxhook |= 0x14;
- wc->sethook[chan_idx] = CMD_WR(64, wc->mods[chan_idx].fxs.lasttxhook);
- }
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) &&
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) {
+ x = fxs->lasttxhook;
+ x |= SLIC_LF_REVMASK;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan_idx]);
+ }
} else {
- wc->mods[chan_idx].fxs.idletxhookstate &= ~0x04;
+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK;
/* Do not set while currently ringing or open */
- if (wc->mods[chan_idx].fxs.lasttxhook != 0x04 &&
- wc->mods[chan_idx].fxs.lasttxhook != 0x00) {
- x = wc->mods[chan_idx].fxs.lasttxhook;
- x &= ~0x04;
- x |= 0x10;
- wc->mods[chan_idx].fxs.lasttxhook = x;
- wc->sethook[chan_idx] = CMD_WR(64, wc->mods[chan_idx].fxs.lasttxhook);
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) &&
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) {
+ x = fxs->lasttxhook;
+ x &= ~SLIC_LF_REVMASK;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan_idx]);
}
}
if (debug) {
- printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, lrev=%d\n",
- chan_idx,
- wc->mods[chan_idx].fxs.vmwi_active_messages,
- wc->mods[chan_idx].fxs.vmwi_linereverse
- );
+ printk(KERN_DEBUG
+ "Setting VMWI on channel %d, messages=%d, lrev=%d\n",
+ chan_idx, fxs->vmwi_active_messages,
+ fxs->vmwi_linereverse);
}
return 0;
}
@@ -2282,11 +2347,10 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
/* By default, don't send on hook */
if (!reversepolarity != !wc->mods[card].fxs.reversepolarity) {
- wc->mods[card].fxs.idletxhookstate = 5;
+ wc->mods[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_REV;
} else {
- wc->mods[card].fxs.idletxhookstate = 1;
+ wc->mods[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_FWD;
}
- wc->mods[card].fxs.lasttxhook = 0x10;
if (sane) {
/* Make sure we turn off the DC->DC converter to prevent anything from blowing up */
@@ -2329,6 +2393,7 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
}
if (!fast) {
+ spin_lock_init(&wc->mods[card].fxs.lasttxhooklock);
/* Check for power leaks */
if (wctdm_proslic_powerleak_test(wc, card)) {
@@ -2504,7 +2569,7 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
printk(KERN_DEBUG "DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
wc->mods[card].fxs.lasttxhook = wc->mods[card].fxs.idletxhookstate;
- wctdm_setreg(wc, card, 64, wc->mods[card].fxs.lasttxhook);
+ wctdm_setreg(wc, card, LINE_STATE, wc->mods[card].fxs.lasttxhook);
return 0;
}
@@ -2653,6 +2718,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
struct dahdi_radio_stat s;
struct dahdi_radio_param p;
} stack;
+ struct fxs *const fxs = &wc->mods[chan->chanpos - 1].fxs;
switch (cmd) {
case DAHDI_ONHOOKTRANSFER:
@@ -2660,19 +2726,27 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
return -EINVAL;
if (get_user(x, (__user int *) data))
return -EFAULT;
- wc->mods[chan->chanpos - 1].fxs.ohttimer = x << 3;
- wc->mods[chan->chanpos - 1].fxs.idletxhookstate = 0x2; /* OHT mode when idle */
- if (wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x5) {
- /* Apply the change if appropriate */
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos -1) ? 0x16 : 0x12;
- wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
- /* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */
+ fxs->ohttimer = x << 3;
+
+ /* Active mode when idle */
+ fxs->idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ?
+ SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
+
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_FWD) ||
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_REV)) {
+
+ set_lasttxhook_interruptible(fxs, POLARITY_XOR(chan->chanpos - 1)
+ ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD ,
+ &wc->sethook[chan->chanpos - 1]);
}
break;
case DAHDI_VMWI_CONFIG:
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
return -EINVAL;
- if (copy_from_user(&(wc->mods[chan->chanpos - 1].fxs.vmwisetting), (__user void *) data, sizeof(wc->mods[chan->chanpos - 1].fxs.vmwisetting)))
+ if (copy_from_user(&(fxs->vmwisetting),
+ (__user void *)data,
+ sizeof(fxs->vmwisetting)))
return -EFAULT;
set_vmwi(wc, chan->chanpos - 1);
break;
@@ -2683,7 +2757,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
return -EFAULT;
if (0 > x)
return -EFAULT;
- wc->mods[chan->chanpos - 1].fxs.vmwi_active_messages = x;
+ fxs->vmwi_active_messages = x;
set_vmwi(wc, chan->chanpos - 1);
break;
case WCTDM_GET_STATS:
@@ -2728,9 +2802,10 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val);
} else {
regop.val &= 0xff;
- if (regop.reg == 64)
- wc->mods[chan->chanpos-1].fxs.lasttxhook = (regop.val & 0x0f) | 0x10;
-
+ if (regop.reg == LINE_STATE) {
+ /* Set feedback register to indicate the new state that is being set */
+ fxs->lasttxhook = (regop.val & 0x0f) | SLIC_LF_OPPENDING;
+ }
printk(KERN_INFO "Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos);
wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val);
}
@@ -2783,25 +2858,23 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
return -EINVAL;
/* Can't change polarity while ringing or when open */
- if ((wc->mods[chan->chanpos -1 ].fxs.lasttxhook == 0x04) ||
- (wc->mods[chan->chanpos -1 ].fxs.lasttxhook == 0x00))
+ if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_RINGING) ||
+ ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_OPEN))
return -EINVAL;
- if (x) {
- wc->mods[chan->chanpos -1 ].fxs.reversepolarity = 1;
- } else {
- wc->mods[chan->chanpos -1 ].fxs.reversepolarity = 0;
- }
+
+ fxs->reversepolarity = (x) ? 1 : 0;
+
if (POLARITY_XOR(chan->chanpos -1)) {
- wc->mods[chan->chanpos -1 ].fxs.idletxhookstate |= 0x14;
- wc->mods[chan->chanpos -1 ].fxs.lasttxhook |= 0x14;
+ fxs->idletxhookstate |= SLIC_LF_REVMASK;
+ x = fxs->lasttxhook;
+ x |= SLIC_LF_REVMASK;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan->chanpos - 1]);
} else {
- wc->mods[chan->chanpos -1 ].fxs.idletxhookstate &= ~0x04;
- x = wc->mods[chan->chanpos -1 ].fxs.lasttxhook;
- x &= ~0x04;
- x |= 0x10;
- wc->mods[chan->chanpos -1 ].fxs.lasttxhook = x;
+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK;
+ x = fxs->lasttxhook;
+ x &= ~SLIC_LF_REVMASK;
+ set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan->chanpos - 1]);
}
- wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
break;
case DAHDI_RADIO_GETPARAM:
if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV)
@@ -2988,7 +3061,9 @@ static int wctdm_close(struct dahdi_chan *chan)
module_put(THIS_MODULE);
for (x=0;x<wc->cards;x++) {
if (wc->modtype[x] == MOD_TYPE_FXS) {
- wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 5 : 1;
+ wc->mods[x].fxs.idletxhookstate =
+ POLARITY_XOR(x) ? SLIC_LF_ACTIVE_REV :
+ SLIC_LF_ACTIVE_FWD;
}
if (wc->modtype[x] == MOD_TYPE_QRV)
{
@@ -3017,6 +3092,7 @@ static int wctdm_close(struct dahdi_chan *chan)
static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
{
struct wctdm *wc = chan->pvt;
+
int reg=0,qrvcard;
if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) {
qrvcard = (chan->chanpos - 1) & 0xfc;
@@ -3052,21 +3128,26 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
default:
printk(KERN_NOTICE "wctdm24xxp: Can't set tx state to %d\n", txsig);
}
- } else {
+ } else { /* Else this is an fxs port */
+ unsigned long flags;
+ struct fxs *const fxs = &wc->mods[chan->chanpos - 1].fxs;
+ spin_lock_irqsave(&fxs->lasttxhooklock, flags);
switch(txsig) {
case DAHDI_TXSIG_ONHOOK:
switch(chan->sig) {
case DAHDI_SIG_EM:
case DAHDI_SIG_FXOKS:
case DAHDI_SIG_FXOLS:
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 |
- wc->mods[chan->chanpos - 1].fxs.idletxhookstate;
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
+ fxs->idletxhookstate;
break;
case DAHDI_SIG_FXOGS:
if (POLARITY_XOR(chan->chanpos -1)) {
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x17;
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
+ SLIC_LF_RING_OPEN;
} else {
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x13;
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
+ SLIC_LF_TIP_OPEN;
}
break;
}
@@ -3075,32 +3156,32 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
switch(chan->sig) {
case DAHDI_SIG_EM:
if (POLARITY_XOR(chan->chanpos -1)) {
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x11;
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
+ SLIC_LF_ACTIVE_FWD;
} else {
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x15;
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
+ SLIC_LF_ACTIVE_REV;
}
break;
default:
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 |
- wc->mods[chan->chanpos - 1].fxs.idletxhookstate;
+ fxs->lasttxhook = SLIC_LF_OPPENDING |
+ fxs->idletxhookstate;
break;
}
break;
case DAHDI_TXSIG_START:
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x14;
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_RINGING;
break;
case DAHDI_TXSIG_KEWL:
- wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10;
+ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_OPEN;
break;
default:
printk(KERN_NOTICE "wctdm24xxp: Can't set tx state to %d\n", txsig);
}
+ wc->sethook[chan->chanpos - 1] = CMD_WR(LINE_STATE, fxs->lasttxhook);
+ spin_unlock_irqrestore(&fxs->lasttxhooklock, flags);
if (debug & DEBUG_CARD)
printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, reg);
-
-
- wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
- /* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */
}
return 0;
}
@@ -3208,12 +3289,14 @@ static int wctdm_initialize(struct wctdm *wc)
/* DAHDI stuff */
sprintf(wc->span.name, "WCTDM/%d", wc->pos);
- snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1,
+ "%s Board %d", wc->desc->name, wc->pos + 1);
snprintf(wc->span.location, sizeof(wc->span.location) - 1,
"PCI%s Bus %02d Slot %02d", (wc->flags[0] & FLAG_EXPRESS) ? " Express" : "",
pdev->bus->number, PCI_SLOT(pdev->devfn) + 1);
wc->span.manufacturer = "Digium";
- strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
+ strncpy(wc->span.devicetype, wc->desc->name,
+ sizeof(wc->span.devicetype) - 1);
if (alawoverride) {
printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n");
wc->span.deflaw = DAHDI_LAW_ALAW;
@@ -3228,7 +3311,7 @@ static int wctdm_initialize(struct wctdm *wc)
wc->chans[x]->pvt = wc;
}
wc->span.chans = wc->chans;
- wc->span.channels = wc->type;
+ wc->span.channels = wc->desc->ports;
wc->span.irq = pdev->irq;
wc->span.hooksig = wctdm_hooksig;
wc->span.open = wctdm_open;
@@ -3387,7 +3470,7 @@ static int wctdm_vpm_init(struct wctdm *wc)
}
printk(KERN_INFO "Enabling VPM100 gain adjustments on any FXO ports found\n");
- for (i = 0; i < wc->type; i++) {
+ for (i = 0; i < wc->desc->ports; i++) {
if (wc->modtype[i] == MOD_TYPE_FXO) {
/* Apply negative Tx gain of 4.5db to DAA */
wctdm_setreg(wc, i, 38, 0x14); /* 4db */
@@ -3477,7 +3560,6 @@ static int wctdm_locate_modules(struct wctdm *wc)
{
int x;
unsigned long flags;
- unsigned int startinglatency = voicebus_current_latency(wc->vb);
wc->ctlreg = 0x00;
/* Make sure all units go into daisy chain mode */
@@ -3503,16 +3585,13 @@ static int wctdm_locate_modules(struct wctdm *wc)
#endif
/* Now that all the cards have been reset, we can stop checking them all if there aren't as many */
spin_lock_irqsave(&wc->reglock, flags);
- wc->cards = wc->type;
+ wc->cards = wc->desc->ports;
spin_unlock_irqrestore(&wc->reglock, flags);
/* Reset modules */
for (x=0;x<wc->cards;x++) {
int sane=0,ret=0,readi=0;
retry:
- if (voicebus_current_latency(wc->vb) > startinglatency) {
- return -EAGAIN;
- }
/* Init with Auto Calibration */
if (!(ret = wctdm_init_proslic(wc, x, 0, 0, sane))) {
wc->cardflag |= (1 << x);
@@ -3545,10 +3624,11 @@ retry:
wc->cardflag |= 1 << x;
printk(KERN_INFO "Port %d: Installed -- QRV DRI card\n",x + 1);
} else {
- if ((wc->type != 24) && ((x & 0x3) == 1) && !wc->altcs[x]) {
- spin_lock_irqsave(&wc->reglock, flags);
+ if ((wc->desc->ports != 24) &&
+ ((x & 0x3) == 1) && !wc->altcs[x]) {
+ spin_lock_irqsave(&wc->reglock, flags);
wc->altcs[x] = 2;
- if (wc->type == 4) {
+ if (wc->desc->ports == 4) {
wc->altcs[x+1] = 3;
wc->altcs[x+2] = 3;
}
@@ -3601,12 +3681,6 @@ retry:
wc->vpmadt032->span = &wc->span;
get_default_portconfig(&portconfig);
res = vpmadt032_init(wc->vpmadt032, wc->vb);
- /* In case there was an error while we were loading the VPM module. */
- if (voicebus_current_latency(wc->vb) > startinglatency) {
- vpmadt032_free(wc->vpmadt032);
- wc->vpmadt032 = NULL;
- return -EAGAIN;
- }
if (res) {
vpmadt032_free(wc->vpmadt032);
wc->vpmadt032 = NULL;
@@ -3636,7 +3710,7 @@ static void free_wc(struct wctdm *wc)
{
unsigned int x;
- for (x = 0; x < sizeof(wc->chans)/sizeof(wc->chans[0]); x++) {
+ for (x = 0; x < ARRAY_SIZE(wc->chans); x++) {
if (wc->chans[x]) {
kfree(wc->chans[x]);
}
@@ -3649,19 +3723,18 @@ static void free_wc(struct wctdm *wc)
static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct wctdm *wc;
- struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data;
int i;
int y;
int ret;
neonmwi_offlimit_cycles = neonmwi_offlimit /MS_PER_HOOKCHECK;
-retry:
if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) {
return -ENOMEM;
}
memset(wc, 0, sizeof(*wc));
+ wc->desc = (struct wctdm_desc *)ent->driver_data;
spin_lock(&ifacelock);
/* \todo this is a candidate for removal... */
for (i = 0; i < WC_MAX_IFACES; ++i) {
@@ -3689,12 +3762,10 @@ retry:
spin_lock_init(&wc->reglock);
wc->curcard = -1;
wc->cards = NUM_CARDS;
- wc->type = d->ports;
wc->pos = i;
- wc->variety = d->name;
wc->txident = 1;
for (y=0;y<NUM_CARDS;y++) {
- wc->flags[y] = d->flags;
+ wc->flags[y] = wc->desc->flags;
wc->dacssrc[y] = -1;
}
@@ -3721,29 +3792,14 @@ retry:
return -EIO;
}
+ voicebus_lock_latency(wc->vb);
- /* Keep track of which device we are */
- pci_set_drvdata(pdev, wc);
-
- /* Start the hardware processing. */
if (voicebus_start(wc->vb)) {
BUG_ON(1);
}
/* Now track down what modules are installed */
- ret = wctdm_locate_modules(wc);
- if (-EAGAIN == ret ) {
- /* The voicebus library increased the latency during
- * initialization. There is a chance that the hardware is in
- * an inconsistent state, so lets increase the default latency
- * and start the initialization over.
- */
- printk(KERN_NOTICE "%s: Restarting board initialization " \
- "after increasing latency.\n", wc->board_name);
- latency = voicebus_current_latency(wc->vb);
- wctdm_release(wc);
- goto retry;
- }
+ wctdm_locate_modules(wc);
/* Final initialization */
wctdm_post_initialize(wc);
@@ -3756,10 +3812,11 @@ retry:
wc->initialized = 1;
- printk(KERN_INFO "Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->type);
- ret = 0;
+ printk(KERN_INFO "Found a Wildcard TDM: %s (%d modules)\n",
+ wc->desc->name, wc->desc->ports);
- return ret;
+ voicebus_unlock_latency(wc->vb);
+ return 0;
}
static void wctdm_release(struct wctdm *wc)
@@ -3785,7 +3842,7 @@ static void wctdm_release(struct wctdm *wc)
static void __devexit wctdm_remove_one(struct pci_dev *pdev)
{
- struct wctdm *wc = pci_get_drvdata(pdev);
+ struct wctdm *wc = voicebus_pci_dev_to_context(pdev);
struct vpmadt032 *vpm = wc->vpmadt032;
if (wc) {
@@ -3837,15 +3894,15 @@ static int __init wctdm_init(void)
int res;
int x;
- for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
+ for (x = 0; x < ARRAY_SIZE(fxo_modes); x++) {
if (!strcmp(fxo_modes[x].name, opermode))
break;
}
- if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {
+ if (x < ARRAY_SIZE(fxo_modes)) {
_opermode = x;
} else {
printk(KERN_NOTICE "Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode);
- for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
+ for (x = 0; x < ARRAY_SIZE(fxo_modes); x++)
printk(KERN_NOTICE " %s\n", fxo_modes[x].name);
printk(KERN_NOTICE "Note this option is CASE SENSITIVE!\n");
return -ENODEV;
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index 3d08bef..bf0c17b 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -141,7 +141,7 @@ enum battery_state {
};
struct wctdm {
- char *variety;
+ const struct wctdm_desc *desc;
char board_name[80];
struct dahdi_span span;
unsigned char ios;
@@ -202,7 +202,17 @@ struct wctdm {
int debounce;
int ohttimer;
int idletxhookstate; /* IDLE changing hook state */
- int lasttxhook; /* Bits 0-3 are written to proslic reg 64, Bit 4 indicates if the last write is pending */
+ /* lasttxhook reflects the last value written to the proslic's reg
+ * 64 (LINEFEED_CONTROL) in bits 0-2. Bit 4 indicates if the last
+ * write is pending i.e. it is in process of being written to the
+ * register
+ * NOTE: in order for this value to actually be written to the
+ * proslic, the appropriate matching value must be written into the
+ * sethook variable so that it gets queued and handled by the
+ * voicebus ISR.
+ */
+ int lasttxhook;
+ spinlock_t lasttxhooklock;
int palarms;
struct dahdi_vmwi_info vmwisetting;
int vmwi_active_messages;
@@ -217,17 +227,9 @@ struct wctdm {
/* Set hook */
int sethook[NUM_CARDS + NUM_EC];
int dacssrc[NUM_CARDS];
- /* Type is the maximum number of FXO/FXS ports supported */
- int type;
int vpm100;
- unsigned long dtmfactive;
- unsigned long dtmfmask;
- unsigned long dtmfmutemask;
- short dtmfenergy[NUM_CARDS];
- short dtmfdigit[NUM_CARDS];
-
struct vpmadt032 *vpmadt032;
#ifdef FANCY_ECHOCAN
int echocanpos;
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index 2f16b3a..5e0854f 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -53,7 +53,10 @@ struct pci_driver te12xp_driver;
int debug = 0;
static int j1mode = 0;
-static int alarmdebounce = 0;
+static int alarmdebounce = 2500; /* LOF/LFA def to 2.5s AT&T TR54016*/
+static int losalarmdebounce = 2500; /* LOS def to 2.5s AT&T TR54016*/
+static int aisalarmdebounce = 2500; /* AIS(blue) def to 2.5s AT&T TR54016*/
+static int yelalarmdebounce = 500; /* RAI(yellow) def to 0.5s AT&T devguide */
static int loopback = 0;
static int t1e1override = -1;
static int unchannelized = 0;
@@ -84,13 +87,12 @@ struct t1 *ifaces[WC_MAX_IFACES];
spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
struct t1_desc {
- char *name;
- int flags;
+ const char *name;
};
-static struct t1_desc te120p = { "Wildcard TE120P", 0 };
-static struct t1_desc te122 = { "Wildcard TE122", 0 };
-static struct t1_desc te121 = { "Wildcard TE121", 0 };
+static const struct t1_desc te120p = {"Wildcard TE120P"};
+static const struct t1_desc te122 = {"Wildcard TE122"};
+static const struct t1_desc te121 = {"Wildcard TE121"};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static kmem_cache_t *cmd_cache;
@@ -490,7 +492,6 @@ static void cmd_dequeue_vpmadt032(struct t1 *wc, unsigned char *writechunk, int
writechunk[CMD_BYTE(4, 2, 1)] = 0;
}
} else if (test_and_clear_bit(VPM150M_SWRESET, &vpm->control)) {
- debug_printk(1, "Booting VPMADT032\n");
for (x = 0; x < 7; x++) {
if (0 == x) {
writechunk[CMD_BYTE(x, 0, 1)] = (0x8 << 4);
@@ -729,7 +730,7 @@ static void t1_configure_t1(struct t1 *wc, int lineconfig, int txlevel)
else
mytxlevel = txlevel - 4;
fmr1 = 0x9e; /* FMR1: Mode 0, T1 mode, CRC on for ESF, 2.048 Mhz system data rate, no XAIS */
- fmr2 = 0x22; /* FMR2: no payload loopback, auto send yellow alarm */
+ fmr2 = 0x20; /* FMR2: no payload loopback, don't auto yellow alarm */
if (loopback)
fmr2 |= 0x4;
@@ -1188,7 +1189,7 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec
if (!wc->vpmadt032)
return;
- vpmadt032_echocan_free(wc->vpmadt032, chan, ec);
+ vpmadt032_echocan_free(wc->vpmadt032, chan->chanpos - 1, ec);
}
static void set_span_devicetype(struct t1 *wc)
@@ -1487,16 +1488,48 @@ static inline void t1_check_alarms(struct t1 *wc)
alarms |= DAHDI_ALARM_NOTOPEN;
}
- if (c & 0xa0) {
- if (wc->alarmcount >= alarmdebounce) {
- if (!unchannelized)
- alarms |= DAHDI_ALARM_RED;
- } else
+ if (c & 0x20) { /* LOF/LFA */
+ if (wc->alarmcount >= (alarmdebounce/100))
+ alarms |= DAHDI_ALARM_RED;
+ else {
+ if (unlikely(debug && !wc->alarmcount)) {
+ /* starting to debounce LOF/LFA */
+ t1_info(wc, "LOF/LFA detected but "
+ "debouncing for %d ms\n",
+ alarmdebounce);
+ }
wc->alarmcount++;
+ }
} else
wc->alarmcount = 0;
- if (c & 0x4)
- alarms |= DAHDI_ALARM_BLUE;
+
+ if (c & 0x80) { /* LOS */
+ if (wc->losalarmcount >= (losalarmdebounce/100))
+ alarms |= DAHDI_ALARM_RED;
+ else {
+ if (unlikely(debug && !wc->losalarmcount)) {
+ /* starting to debounce LOS */
+ t1_info(wc, "LOS detected but debouncing "
+ "for %d ms\n", losalarmdebounce);
+ }
+ wc->losalarmcount++;
+ }
+ } else
+ wc->losalarmcount = 0;
+
+ if (c & 0x40) { /* AIS */
+ if (wc->aisalarmcount >= (aisalarmdebounce/100))
+ alarms |= DAHDI_ALARM_BLUE;
+ else {
+ if (unlikely(debug && !wc->aisalarmcount)) {
+ /* starting to debounce AIS */
+ t1_info(wc, "AIS detected but debouncing "
+ "for %d ms\n", aisalarmdebounce);
+ }
+ wc->aisalarmcount++;
+ }
+ } else
+ wc->aisalarmcount = 0;
/* Keep track of recovering */
if ((!alarms) && wc->span.alarms)
@@ -1517,9 +1550,26 @@ static inline void t1_check_alarms(struct t1 *wc)
t1_setreg_full(wc, 0x20, fmr4 & ~0x20, NOT_VPM);
wc->flags.sendingyellow = 0;
}
-
+ /*
if ((c & 0x10) && !unchannelized)
alarms |= DAHDI_ALARM_YELLOW;
+ */
+
+ if ((c & 0x10) && !unchannelized) { /* receiving yellow (RAI) */
+ if (wc->yelalarmcount >= (yelalarmdebounce/100))
+ alarms |= DAHDI_ALARM_YELLOW;
+ else {
+ if (unlikely(debug && !wc->yelalarmcount)) {
+ /* starting to debounce AIS */
+ t1_info(wc, "yelllow (RAI) detected but "
+ "debouncing for %d ms\n",
+ yelalarmdebounce);
+ }
+ wc->yelalarmcount++;
+ }
+ } else
+ wc->yelalarmcount = 0;
+
if (wc->span.mainttimer || wc->span.maintstat)
alarms |= DAHDI_ALARM_LOOPBACK;
wc->span.alarms = alarms;
@@ -1685,13 +1735,13 @@ static void timer_work_func(struct work_struct *work)
{
struct t1 *wc = container_of(work, struct t1, timer_work);
#endif
- /* Called once every 100ms */
+ /* Called once every 100 ms */
if (unlikely(!test_bit(INITIALIZED, &wc->bit_flags)))
return;
t1_do_counters(wc);
t1_check_alarms(wc);
t1_check_sigbits(wc);
- mod_timer(&wc->timer, jiffies + HZ/5);
+ mod_timer(&wc->timer, jiffies + HZ/10);
}
static void
@@ -1708,7 +1758,6 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi
struct t1_desc *d = (struct t1_desc *) ent->driver_data;
unsigned int x;
int res;
- int startinglatency;
unsigned int index = -1;
for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++) {
@@ -1723,7 +1772,6 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi
return -EIO;
}
-retry:
if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) {
return -ENOMEM;
}
@@ -1763,13 +1811,12 @@ retry:
return res;
}
- /* Keep track of which device we are */
- pci_set_drvdata(pdev, wc);
if (VOICEBUS_DEFAULT_LATENCY != latency) {
voicebus_set_minlatency(wc->vb, latency);
}
+
+ voicebus_lock_latency(wc->vb);
voicebus_start(wc->vb);
- startinglatency = voicebus_current_latency(wc->vb);
t1_hardware_post_init(wc);
for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) {
@@ -1789,31 +1836,14 @@ retry:
mod_timer(&wc->timer, jiffies + HZ/5);
t1_software_init(wc);
- if (voicebus_current_latency(wc->vb) > startinglatency) {
- /* The voicebus library increased the latency during
- * initialization because the host wasn't able to service the
- * interrupts from the adapter quickly enough. In this case,
- * we'll increase our latency and restart the initialization.
- */
- printk(KERN_NOTICE "%s: Restarting board initialization " \
- "after increasing latency.\n", wc->name);
- latency = voicebus_current_latency(wc->vb);
- dahdi_unregister(&wc->span);
- voicebus_release(wc->vb);
- wc->vb = NULL;
- free_wc(wc);
- wc = NULL;
- goto retry;
- }
-
module_printk("Found a %s\n", wc->variety);
-
+ voicebus_unlock_latency(wc->vb);
return 0;
}
static void __devexit te12xp_remove_one(struct pci_dev *pdev)
{
- struct t1 *wc = pci_get_drvdata(pdev);
+ struct t1 *wc = voicebus_pci_dev_to_context(pdev);
#ifdef VPM_SUPPORT
unsigned long flags;
struct vpmadt032 *vpm = wc->vpmadt032;
@@ -1902,6 +1932,9 @@ module_param(loopback, int, S_IRUGO | S_IWUSR);
module_param(t1e1override, int, S_IRUGO | S_IWUSR);
module_param(j1mode, int, S_IRUGO | S_IWUSR);
module_param(alarmdebounce, int, S_IRUGO | S_IWUSR);
+module_param(losalarmdebounce, int, S_IRUGO | S_IWUSR);
+module_param(aisalarmdebounce, int, S_IRUGO | S_IWUSR);
+module_param(yelalarmdebounce, int, S_IRUGO | S_IWUSR);
module_param(latency, int, S_IRUGO | S_IWUSR);
#ifdef VPM_SUPPORT
module_param(vpmsupport, int, S_IRUGO | S_IWUSR);
diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h
index 2a0a0f4..ceb309a 100644
--- a/drivers/dahdi/wcte12xp/wcte12xp.h
+++ b/drivers/dahdi/wcte12xp/wcte12xp.h
@@ -113,7 +113,10 @@ struct t1 {
} flags;
unsigned char txsigs[16]; /* Copy of tx sig registers */
int alarmcount; /* How much red alarm we've seen */
- char *variety;
+ int losalarmcount;
+ int aisalarmcount;
+ int yelalarmcount;
+ const char *variety;
char name[80];
unsigned long blinktimer;
int loopupcnt;
@@ -144,7 +147,7 @@ struct t1 {
struct work_struct timer_work;
};
-
-int schluffen(wait_queue_head_t *q);
+#define t1_info(t1, format, arg...) \
+ dev_info(&voicebus_get_pci_dev(t1->vb)->dev , format , ## arg)
#endif
diff --git a/drivers/dahdi/xpp/xdefs.h b/drivers/dahdi/xpp/xdefs.h
index ad89d4c..24b2291 100644
--- a/drivers/dahdi/xpp/xdefs.h
+++ b/drivers/dahdi/xpp/xdefs.h
@@ -138,11 +138,6 @@ typedef unsigned char byte;
#define DRIVER_ATTR_READER(name,drv,buf) \
ssize_t name(struct device_driver *drv, char * buf)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-#define dev_name(dev) (dev)->bus_id
-#define dev_set_name(dev, format, ...) \
- snprintf((dev)->bus_id, BUS_ID_SIZE, format, ## __VA_ARGS__);
-#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
#define SET_PROC_DIRENTRY_OWNER(p) do { (p)->owner = THIS_MODULE; } while(0);
#else
diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
index 0731056..6058779 100644
--- a/include/dahdi/kernel.h
+++ b/include/dahdi/kernel.h
@@ -85,6 +85,12 @@
#endif
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+#define dev_name(dev) (dev)->bus_id
+#define dev_set_name(dev, format, ...) \
+ snprintf((dev)->bus_id, BUS_ID_SIZE, format, ## __VA_ARGS__);
+#endif
+
/*! Default chunk size for conferences and such -- static right now, might make
variable sometime. 8 samples = 1 ms = most frequent service interval possible
for a USB device */
@@ -1166,4 +1172,8 @@ static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss)
#define kzalloc(a, b) kcalloc(1, a, b)
#endif
+#ifndef DMA_BIT_MASK
+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+#endif
+
#endif /* _DAHDI_KERNEL_H */
diff --git a/include/dahdi/user.h b/include/dahdi/user.h
index 5c7121a..1d0570a 100644
--- a/include/dahdi/user.h
+++ b/include/dahdi/user.h
@@ -1027,19 +1027,6 @@ struct dahdi_vmwi_info {
#define DAHDI_ECHOCANCEL_FAX_MODE _IOW(DAHDI_CODE, 102, int)
-struct torisa_debug {
- unsigned int txerrors;
- unsigned int irqcount;
- unsigned int taskletsched;
- unsigned int taskletrun;
- unsigned int taskletexec;
- int span1flags;
- int span2flags;
-};
-
-/* Special torisa ioctl */
-#define TORISA_GETDEBUG _IOW(DAHDI_CODE, 60, struct torisa_debug)
-
/* Get current status IOCTL */
/* Defines for Radio Status (dahdi_radio_stat.radstat) bits */