summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/dahdi/voicebus/voicebus.c105
-rw-r--r--drivers/dahdi/voicebus/voicebus.h15
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c36
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h3
-rw-r--r--drivers/dahdi/wcte12xp/base.c54
-rw-r--r--drivers/dahdi/wcte12xp/wcte12xp.h8
6 files changed, 216 insertions, 5 deletions
diff --git a/drivers/dahdi/voicebus/voicebus.c b/drivers/dahdi/voicebus/voicebus.c
index 9bc7386..351ccc9 100644
--- a/drivers/dahdi/voicebus/voicebus.c
+++ b/drivers/dahdi/voicebus/voicebus.c
@@ -94,6 +94,111 @@
#define OWN_BIT (1 << 31)
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+
+/*
+ * These dahdi_fifo_xxx functions are currently only used by the voicebus
+ * drivers, but are named more generally to facilitate moving out in the
+ * future. They probably also could stand to be changed in order to use a
+ * kfifo implementation from the kernel if one is available.
+ *
+ */
+
+struct dahdi_fifo {
+ size_t total_size;
+ u32 start;
+ u32 end;
+ u8 data[0];
+};
+
+static unsigned int dahdi_fifo_used_space(struct dahdi_fifo *fifo)
+{
+ return (fifo->end >= fifo->start) ? fifo->end - fifo->start :
+ fifo->total_size - fifo->start + fifo->end;
+}
+
+unsigned int __dahdi_fifo_put(struct dahdi_fifo *fifo, u8 *data, size_t size)
+{
+ int newinsertposition;
+ int cpy_one_len, cpy_two_len;
+
+ if ((size + dahdi_fifo_used_space(fifo)) > (fifo->total_size - 1))
+ return -1;
+
+ if ((fifo->end + size) >= fifo->total_size) {
+ cpy_one_len = fifo->total_size - fifo->end;
+ cpy_two_len = fifo->end + size - fifo->total_size;
+ newinsertposition = cpy_two_len;
+ } else {
+ cpy_one_len = size;
+ cpy_two_len = 0;
+ newinsertposition = fifo->end + size;
+ }
+
+ memcpy(&fifo->data[fifo->end], data, cpy_one_len);
+
+ if (cpy_two_len)
+ memcpy(&fifo->data[0], &data[cpy_one_len], cpy_two_len);
+
+ fifo->end = newinsertposition;
+
+ return size;
+}
+EXPORT_SYMBOL(__dahdi_fifo_put);
+
+unsigned int __dahdi_fifo_get(struct dahdi_fifo *fifo, u8 *data, size_t size)
+{
+ int newbegin;
+ int cpy_one_len, cpy_two_len;
+
+ if (size > dahdi_fifo_used_space(fifo))
+ return 0;
+
+ if ((fifo->start + size) >= fifo->total_size) {
+ cpy_one_len = fifo->total_size - fifo->start;
+ cpy_two_len = fifo->start + size - fifo->total_size;
+ newbegin = cpy_two_len;
+ } else {
+ cpy_one_len = size;
+ cpy_two_len = 0;
+ newbegin = fifo->start + size;
+ }
+
+ memcpy(&data[0], &fifo->data[fifo->start], cpy_one_len);
+
+ if (cpy_two_len)
+ memcpy(&data[cpy_one_len], &fifo->data[0], cpy_two_len);
+
+ fifo->start = newbegin;
+
+ return size;
+}
+EXPORT_SYMBOL(__dahdi_fifo_get);
+
+void dahdi_fifo_free(struct dahdi_fifo *fifo)
+{
+ kfree(fifo);
+}
+EXPORT_SYMBOL(dahdi_fifo_free);
+
+struct dahdi_fifo *dahdi_fifo_alloc(u32 maxsize, gfp_t alloc_flags)
+{
+ struct dahdi_fifo *fifo;
+
+ fifo = kmalloc(maxsize + sizeof(*fifo) + 1, alloc_flags);
+
+ if (!fifo)
+ return NULL;
+
+ fifo->start = fifo->end = 0;
+ fifo->total_size = maxsize + 1;
+
+ return fifo;
+}
+EXPORT_SYMBOL(dahdi_fifo_alloc);
+#endif /* CONFIG_VOICEBUS_ECREFERENCE */
+
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
kmem_cache_t *voicebus_vbb_cache;
#else
diff --git a/drivers/dahdi/voicebus/voicebus.h b/drivers/dahdi/voicebus/voicebus.h
index 6c67f15..53714f6 100644
--- a/drivers/dahdi/voicebus/voicebus.h
+++ b/drivers/dahdi/voicebus/voicebus.h
@@ -62,6 +62,21 @@
* (and not tasklet). */
#define CONFIG_VOICEBUS_INTERRUPT
+/* Define this to use a FIFO for the software echocan reference.
+ * (experimental) */
+#undef CONFIG_VOICEBUS_ECREFERENCE
+
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+
+struct dahdi_fifo;
+unsigned int __dahdi_fifo_put(struct dahdi_fifo *fifo, u8 *data, size_t size);
+unsigned int __dahdi_fifo_get(struct dahdi_fifo *fifo, u8 *data, size_t size);
+void dahdi_fifo_free(struct dahdi_fifo *fifo);
+struct dahdi_fifo *dahdi_fifo_alloc(size_t maxsize, gfp_t alloc_flags);
+
+#endif
+
+
struct voicebus;
struct vbb {
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 4a7f1fd..eefba37 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -943,6 +943,13 @@ static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechun
}
}
insert_tdm_data(wc, writechunk);
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ for (x = 0; x < wc->avchannels; ++x) {
+ __dahdi_fifo_put(wc->ec_reference[x],
+ wc->chans[x]->chan.writechunk,
+ DAHDI_CHUNKSIZE);
+ }
+#endif
}
for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
@@ -1192,7 +1199,14 @@ static inline void wctdm_receiveprep(struct wctdm *wc, const u8 *readchunk)
if (likely(wc->initialized)) {
for (x = 0; x < wc->avchannels; x++) {
struct dahdi_chan *c = &wc->chans[x]->chan;
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ unsigned char buffer[DAHDI_CHUNKSIZE];
+ __dahdi_fifo_get(wc->ec_reference[x], buffer,
+ ARRAY_SIZE(buffer));
+ dahdi_ec_chunk(c, c->readchunk, buffer);
+#else
dahdi_ec_chunk(c, c->readchunk, c->writechunk);
+#endif
}
for (x = 0; x < MAX_SPANS; x++) {
@@ -4317,6 +4331,12 @@ static void wctdm_back_out_gracefully(struct wctdm *wc)
LIST_HEAD(local_list);
voicebus_release(&wc->vb);
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ for (i = 0; i < ARRAY_SIZE(wc->ec_reference); ++i) {
+ if (wc->ec_reference[i])
+ dahdi_fifo_free(wc->ec_reference[i]);
+ }
+#endif
for (i = 0; i < ARRAY_SIZE(wc->spans); ++i) {
if (wc->spans[i] && wc->spans[i]->span.chans)
@@ -4872,6 +4892,22 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
up(&ifacelock);
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ for (i = 0; i < ARRAY_SIZE(wc->ec_reference); ++i) {
+ /* 256 is the smallest power of 2 that will contains the
+ * maximum possible amount of latency. */
+ wc->ec_reference[i] = dahdi_fifo_alloc(256, GFP_KERNEL);
+
+ if (IS_ERR(wc->ec_reference[i])) {
+ ret = PTR_ERR(wc->ec_reference[i]);
+ wc->ec_reference[i] = NULL;
+ wctdm_back_out_gracefully(wc);
+ return ret;
+ }
+ }
+#endif
+
+
wc->desc = (struct wctdm_desc *)ent->driver_data;
/* This is to insure that the analog span is given lowest priority */
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index 1452850..ebacff1 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -269,6 +269,9 @@ struct wctdm {
struct wctdm_span *aspan; /* pointer to the spans[] holding the analog span */
struct wctdm_span *spans[MAX_SPANS];
struct wctdm_chan *chans[NUM_MODULES];
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ struct dahdi_fifo *ec_reference[NUM_MODULES];
+#endif
/* Only care about digital spans here */
/* int span_timing_prio[MAX_SPANS - 1]; */
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index 03f40ae..46cd955 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -710,6 +710,13 @@ static void free_wc(struct t1 *wc)
if (wc->wq)
destroy_workqueue(wc->wq);
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ for (x = 0; x < ARRAY_SIZE(wc->ec_reference); ++x) {
+ if (wc->ec_reference[x])
+ dahdi_fifo_free(wc->ec_reference[x]);
+ }
+#endif
+
kfree(wc);
}
@@ -952,16 +959,20 @@ static void set_span_devicetype(struct t1 *wc)
static int t1xxp_startup(struct dahdi_span *span)
{
struct t1 *wc = container_of(span, struct t1, span);
- int i;
+#ifndef CONFIG_VOICEBUS_ECREFERENCE
+ unsigned int i;
+#endif
check_and_load_vpm(wc);
set_span_devicetype(wc);
+#ifndef CONFIG_VOICEBUS_ECREFERENCE
/* initialize the start value for the entire chunk of last ec buffer */
for (i = 0; i < span->channels; i++) {
memset(wc->ec_chunk1[i], DAHDI_LIN2X(0, span->chans[i]), DAHDI_CHUNKSIZE);
memset(wc->ec_chunk2[i], DAHDI_LIN2X(0, span->chans[i]), DAHDI_CHUNKSIZE);
}
+#endif
/* Reset framer with proper parameters and start */
t1xxp_framer_start(wc, span);
@@ -1901,6 +1912,13 @@ static inline void t1_transmitprep(struct t1 *wc, u8 *writechunk)
dahdi_transmit(&wc->span);
}
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ for (chan = 0; chan < wc->span.channels; chan++) {
+ __dahdi_fifo_put(wc->ec_reference[chan],
+ wc->chans[chan]->writechunk, DAHDI_CHUNKSIZE);
+ }
+#endif
+
for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
if (likely(test_bit(INITIALIZED, &wc->bit_flags))) {
for (chan = 0; chan < wc->span.channels; chan++)
@@ -1924,6 +1942,8 @@ static inline void t1_transmitprep(struct t1 *wc, u8 *writechunk)
}
writechunk += (EFRAME_SIZE + EFRAME_GAP);
}
+
+
}
/**
@@ -1978,11 +1998,23 @@ static inline void t1_receiveprep(struct t1 *wc, const u8* readchunk)
/* echo cancel */
if (likely(test_bit(INITIALIZED, &wc->bit_flags))) {
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ unsigned char buffer[DAHDI_CHUNKSIZE];
+ for (x = 0; x < wc->span.channels; x++) {
+ __dahdi_fifo_get(wc->ec_reference[x], buffer,
+ ARRAY_SIZE(buffer));
+ dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk,
+ buffer);
+ }
+#else
for (x = 0; x < wc->span.channels; x++) {
dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->ec_chunk2[x]);
- memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],DAHDI_CHUNKSIZE);
- memcpy(wc->ec_chunk1[x],wc->chans[x]->writechunk,DAHDI_CHUNKSIZE);
+ memcpy(wc->ec_chunk2[x], wc->ec_chunk1[x],
+ DAHDI_CHUNKSIZE);
+ memcpy(wc->ec_chunk1[x], wc->chans[x]->writechunk,
+ DAHDI_CHUNKSIZE);
}
+#endif
dahdi_receive(&wc->span);
}
}
@@ -2263,6 +2295,22 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi
INIT_WORK(&wc->vpm_check_work, vpm_check_func);
# endif
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ for (x = 0; x < ARRAY_SIZE(wc->ec_reference); ++x) {
+ /* 256 is used here since it is the largest power of two that
+ * will contain 8 * VOICBUS_DEFAULT_LATENCY */
+ wc->ec_reference[x] = dahdi_fifo_alloc(256, GFP_KERNEL);
+
+ if (IS_ERR(wc->ec_reference[x])) {
+ res = PTR_ERR(wc->ec_reference[x]);
+ wc->ec_reference[x] = NULL;
+ free_wc(wc);
+ return res;
+ }
+
+ }
+#endif /* CONFIG_VOICEBUS_ECREFERENCE */
+
snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", index);
pci_set_drvdata(pdev, wc);
wc->vb.ops = &voicebus_operations;
diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h
index 5994fa2..8c04afe 100644
--- a/drivers/dahdi/wcte12xp/wcte12xp.h
+++ b/drivers/dahdi/wcte12xp/wcte12xp.h
@@ -116,11 +116,15 @@ struct t1 {
unsigned long bit_flags;
unsigned long alarmtimer;
unsigned char ledstate;
- unsigned char ec_chunk1[32][DAHDI_CHUNKSIZE];
- unsigned char ec_chunk2[32][DAHDI_CHUNKSIZE];
struct dahdi_span span; /* Span */
struct dahdi_chan *chans[32]; /* Channels */
struct dahdi_echocan_state *ec[32]; /* Echocan state for channels */
+#ifdef CONFIG_VOICEBUS_ECREFERENCE
+ struct dahdi_fifo *ec_reference[32];
+#else
+ unsigned char ec_chunk1[32][DAHDI_CHUNKSIZE];
+ unsigned char ec_chunk2[32][DAHDI_CHUNKSIZE];
+#endif
unsigned long ctlreg;
struct voicebus vb;
atomic_t txints;