[svn-commits] sruffell: linux/trunk r8123 - in /linux/trunk/drivers/dahdi: voicebus/ vpmadt...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Feb 26 10:40:54 CST 2010


Author: sruffell
Date: Fri Feb 26 10:40:44 2010
New Revision: 8123

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8123
Log:
wctdm24xxp: Add support for Hx8 series cards.

The Hx8 series cards support BRI modules in addition to analog modules.

Added:
    linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.c   (with props)
    linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.h   (with props)
Modified:
    linux/trunk/drivers/dahdi/voicebus/voicebus.c
    linux/trunk/drivers/dahdi/voicebus/voicebus.h
    linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c
    linux/trunk/drivers/dahdi/wctdm24xxp/Kbuild
    linux/trunk/drivers/dahdi/wctdm24xxp/base.c
    linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
    linux/trunk/drivers/dahdi/wcte12xp/base.c

Modified: linux/trunk/drivers/dahdi/voicebus/voicebus.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/voicebus.c?view=diff&rev=8123&r1=8122&r2=8123
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.c Fri Feb 26 10:40:44 2010
@@ -95,10 +95,11 @@
 #define OWN_BIT (1 << 31)
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-static kmem_cache_t *buffer_cache;
+kmem_cache_t *voicebus_vbb_cache;
 #else
-static struct kmem_cache *buffer_cache;
-#endif
+struct kmem_cache *voicebus_vbb_cache;
+#endif
+EXPORT_SYMBOL(voicebus_vbb_cache);
 
 /* In memory structure shared by the host and the adapter. */
 struct voicebus_descriptor {
@@ -365,8 +366,6 @@
 	struct voicebus_descriptor *d;
 	unsigned long flags;
 
-	WARN_ON(!vb_is_stopped(vb));
-
 	spin_lock_irqsave(&vb->lock, flags);
 	for (i = 0; i < DRING_SIZE; ++i) {
 		d = vb_descriptor(dl, i);
@@ -374,7 +373,7 @@
 			WARN_ON(!dl->pending[i]);
 			dma_unmap_single(&vb->pdev->dev, d->buffer1,
 					 VOICEBUS_SFRAME_SIZE, DMA_TO_DEVICE);
-			voicebus_free(vb, dl->pending[i]);
+			kmem_cache_free(voicebus_vbb_cache, dl->pending[i]);
 		}
 		if (!test_bit(VOICEBUS_NORMAL_MODE, &vb->flags)) {
 			d->buffer1 = 0;
@@ -388,8 +387,6 @@
 		}
 	}
 
-	/* Send out two idle buffers to start because sometimes the first buffer
-	 * doesn't make it back to us. */
 	dl->head = dl->tail = 0;
 	spin_unlock_irqrestore(&vb->lock, flags);
 	atomic_set(&dl->count, 0);
@@ -402,8 +399,6 @@
 	struct voicebus_descriptor_list *dl = &vb->rxd;
 	struct voicebus_descriptor *d;
 	unsigned long flags;
-
-	BUG_ON(!vb_is_stopped(vb));
 
 	spin_lock_irqsave(&vb->lock, flags);
 	for (i = 0; i < DRING_SIZE; ++i) {
@@ -413,7 +408,7 @@
 					 VOICEBUS_SFRAME_SIZE, DMA_FROM_DEVICE);
 			d->buffer1 = 0;
 			BUG_ON(!dl->pending[i]);
-			kmem_cache_free(buffer_cache, dl->pending[i]);
+			kmem_cache_free(voicebus_vbb_cache, dl->pending[i]);
 			dl->pending[i] = NULL;
 		}
 		d->des0 &= ~OWN_BIT;
@@ -533,7 +528,7 @@
 	unsigned long timeout;
 	u32 reg;
 	u32 pci_access;
-	const u32 DEFAULT_PCI_ACCESS = 0xfff80002;
+	const u32 DEFAULT_PCI_ACCESS = 0xfffc0002;
 	u8 cache_line_size;
 	BUG_ON(in_interrupt());
 
@@ -601,7 +596,7 @@
 	if (unlikely(d->buffer1)) {
 		/* Do not overwrite a buffer that is still in progress. */
 		WARN_ON(1);
-		voicebus_free(vb, vbb);
+		kmem_cache_free(voicebus_vbb_cache, vbb);
 		return -EBUSY;
 	}
 
@@ -614,6 +609,49 @@
 	return 0;
 }
 
+/**
+ * voicebus_transmit - Queue a buffer on the hardware descriptor ring.
+ *
+ */
+int voicebus_transmit(struct voicebus *vb, struct vbb *vbb)
+{
+	struct voicebus_descriptor *d;
+	struct voicebus_descriptor_list *dl = &vb->txd;
+
+	d = vb_descriptor(dl, dl->tail);
+
+	if (unlikely((d->buffer1 != vb->idle_vbb_dma_addr) && d->buffer1)) {
+		if (printk_ratelimit())
+			dev_warn(&vb->pdev->dev, "Dropping tx buffer buffer\n");
+		kmem_cache_free(voicebus_vbb_cache, vbb);
+		/* Schedule the underrun handler to run here, since we'll need
+		 * to cleanup as best we can. */
+		schedule_work(&vb->underrun_work);
+		return -EFAULT;
+	}
+
+	dl->pending[dl->tail] = vbb;
+	d->buffer1 = dma_map_single(&vb->pdev->dev, vbb->data,
+				    sizeof(vbb->data), DMA_TO_DEVICE);
+	dl->tail = (++(dl->tail)) & DRING_MASK;
+	SET_OWNED(d); /* That's it until the hardware is done with it. */
+	atomic_inc(&dl->count);
+	return 0;
+}
+EXPORT_SYMBOL(voicebus_transmit);
+
+
+/*!
+ * \brief Instruct the hardware to check for a new tx descriptor.
+ */
+static inline void
+__vb_tx_demand_poll(struct voicebus *vb)
+{
+	u32 status = __vb_getctl(vb, 0x0028);
+	if ((status & 0x00700000) == 0x00600000)
+		__vb_setctl(vb, 0x0008, 0x00000000);
+}
+
 static void setup_descriptors(struct voicebus *vb)
 {
 	int i;
@@ -631,7 +669,7 @@
 	vb_setctl(vb, 0x0018, (u32)vb->rxd.desc_dma);
 
 	for (i = 0; i < DRING_SIZE; ++i) {
-		vbb = kmem_cache_alloc(buffer_cache, GFP_KERNEL);
+		vbb = kmem_cache_alloc(voicebus_vbb_cache, GFP_KERNEL);
 		if (unlikely(NULL == vbb))
 			BUG_ON(1);
 		list_add_tail(&vbb->entry, &buffers);
@@ -646,13 +684,13 @@
 
 	if (test_bit(VOICEBUS_NORMAL_MODE, &vb->flags)) {
 		for (i = 0; i < vb->min_tx_buffer_count; ++i) {
-			vbb = kmem_cache_alloc(buffer_cache, GFP_KERNEL);
+			vbb = kmem_cache_alloc(voicebus_vbb_cache, GFP_KERNEL);
 			if (unlikely(NULL == vbb))
 				BUG_ON(1);
 			else
 				list_add_tail(&vbb->entry, &buffers);
 		}
-		
+
 		tasklet_disable(&vb->tasklet);
 		handle_transmit(vb, &buffers);
 		tasklet_enable(&vb->tasklet);
@@ -739,55 +777,6 @@
 	printk(KERN_DEBUG "\n\n");
 }
 #endif
-
-/**
- * voicebus_transmit - Queue a buffer on the hardware descriptor ring.
- *
- */
-static int __voicebus_transmit(struct voicebus *vb, struct vbb *vbb)
-{
-	struct voicebus_descriptor *d;
-	struct voicebus_descriptor_list *dl = &vb->txd;
-
-	d = vb_descriptor(dl, dl->tail);
-
-	if (unlikely((d->buffer1 != vb->idle_vbb_dma_addr) && d->buffer1)) {
-		if (printk_ratelimit())
-			dev_warn(&vb->pdev->dev, "Dropping tx buffer buffer\n");
-		voicebus_free(vb, vbb);
-		/* Schedule the underrun handler to run here, since we'll need
-		 * to cleanup as best we can. */
-		schedule_work(&vb->underrun_work);
-		return -EFAULT;
-	}
-
-	dl->pending[dl->tail] = vbb;
-	d->buffer1 = dma_map_single(&vb->pdev->dev, vbb->data,
-				    sizeof(vbb->data), DMA_TO_DEVICE);
-	dl->tail = (++(dl->tail)) & DRING_MASK;
-	SET_OWNED(d); /* That's it until the hardware is done with it. */
-	atomic_inc(&dl->count);
-	return 0;
-}
-
-/*!
- * \brief Instruct the hardware to check for a new tx descriptor.
- */
-static inline void
-__vb_tx_demand_poll(struct voicebus *vb)
-{
-	u32 status = __vb_getctl(vb, 0x0028);
-	if ((status & 0x00700000) == 0x00600000)
-		__vb_setctl(vb, 0x0008, 0x00000000);
-}
-
-int voicebus_transmit(struct voicebus *vb, struct vbb *vbb)
-{
-	__voicebus_transmit(vb, vbb);
-	__vb_tx_demand_poll(vb);
-	return 0;
-}
-EXPORT_SYMBOL(voicebus_transmit);
 
 /*!
  * \brief Remove the next completed transmit buffer (txb) from the tx
@@ -860,18 +849,6 @@
 }
 
 /*!
- * \brief Free a buffer for reuse.
- *
- */
-void
-voicebus_free(struct voicebus *vb, struct vbb *vbb)
-{
-	kmem_cache_free(buffer_cache, vbb);
-}
-EXPORT_SYMBOL(voicebus_free);
-
-
-/*!
  * \brief Command the hardware to check if it owns the next receive
  * descriptor.
  */
@@ -925,11 +902,15 @@
 	/* Start the transmit and receive processors. */
 	reg = __vb_getctl(vb, 0x0030);
 	__vb_setctl(vb, 0x0030, reg|0x00002002);
-	/* Tell the interface to poll the tx and rx descriptors. */
+	__vb_getctl(vb, 0x0030);
 	__vb_rx_demand_poll(vb);
 	__vb_tx_demand_poll(vb);
+	__vb_getctl(vb, 0x0030);
 	VBUNLOCK(vb);
 }
+
+static void vb_tasklet_relaxed(unsigned long data);
+static void vb_tasklet(unsigned long data);
 
 /*!
  * \brief Starts the VoiceBus interface.
@@ -950,6 +931,11 @@
 
 	if (!vb_is_stopped(vb))
 		return -EBUSY;
+
+	if (test_bit(VOICEBUS_NORMAL_MODE, &vb->flags))
+		tasklet_init(&vb->tasklet, vb_tasklet, (unsigned long)vb);
+	else
+		tasklet_init(&vb->tasklet, vb_tasklet_relaxed, (unsigned long)vb);
 
 	ret = vb_reset_interface(vb);
 	if (ret)
@@ -1108,7 +1094,7 @@
 	/* 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 = kmem_cache_alloc(buffer_cache, GFP_ATOMIC);
+		vbb = kmem_cache_alloc(voicebus_vbb_cache, GFP_ATOMIC);
 		WARN_ON(NULL == vbb);
 		if (likely(NULL != vbb))
 			list_add_tail(&vbb->entry, &local);
@@ -1127,29 +1113,64 @@
 	vb->min_tx_buffer_count += increase;
 }
 
-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);
-	}
-}
-
-static inline void vb_set_all_tx_owned(struct voicebus *vb)
-{
-	vb_set_all_owned(vb, &vb->txd);
-}
-
 /**
- * vb_deferred() - Manage the transmit and receive descriptor rings.
- *
- */
-static void vb_deferred(struct voicebus *vb)
-{
+ * vb_tasklet_relaxed() - Service the rings without strict timing requierments.
+ *
+ */
+static void vb_tasklet_relaxed(unsigned long data)
+{
+	struct voicebus *vb = (struct voicebus *)data;
+	LIST_HEAD(buffers);
+	struct vbb *vbb;
+	const int DEFAULT_COUNT = 5;
+	int count = DEFAULT_COUNT;
+	u32 des0 = 0;
+
+	/* 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 ((vbb = vb_get_completed_txb(vb)))
+		list_add_tail(&vbb->entry, &vb->tx_complete);
+
+	while (--count && !list_empty(&vb->tx_complete))
+		list_move_tail(vb->tx_complete.next, &buffers);
+
+	/* Prep all the new buffers for transmit before actually sending any
+	 * of them. */
+	handle_transmit(vb, &buffers);
+
+	list_for_each_entry(vbb, &buffers, entry)
+		voicebus_transmit(vb, vbb);
+	INIT_LIST_HEAD(&buffers);
+
+	/* If there may still be buffers in the descriptor rings, reschedule
+	 * ourself to run again.  We essentially yield here to allow any other
+	 * cards a chance to run. */
+	if (unlikely(!count && !test_bit(VOICEBUS_STOP, &vb->flags)))
+		tasklet_hi_schedule(&vb->tasklet);
+
+	/* And finally, pass up any receive buffers. */
+	count = DEFAULT_COUNT;
+	while (--count && (vbb = vb_get_completed_rxb(vb, &des0))) {
+		if (((des0 >> 16) & 0x7fff) == VOICEBUS_SFRAME_SIZE)
+			list_add_tail(&vbb->entry, &buffers);
+	}
+
+	handle_receive(vb, &buffers);
+	list_for_each_entry(vbb, &buffers, entry)
+		vb_submit_rxb(vb, vbb);
+	return;
+}
+
+static void vb_tasklet(unsigned long data)
+{
+	struct voicebus *vb = (struct voicebus *)data;
 	int softunderrun;
 	LIST_HEAD(buffers);
 	struct vbb *vbb;
@@ -1277,13 +1298,8 @@
 	/* And finally, pass up any receive buffers. */
 	count = DEFAULT_COUNT;
 	while (--count && (vbb = vb_get_completed_rxb(vb, &des0))) {
-		if (((des0 >> 16) & 0x7fff) != VOICEBUS_SFRAME_SIZE) {
-			dev_dbg(&vb->pdev->dev,
-				"ERROR: Dropping packet of wrong size. (%d)\n",
-				(des0>>16)&0x7fff);
-		} else {
+		if (((des0 >> 16) & 0x7fff) == VOICEBUS_SFRAME_SIZE)
 			list_add_tail(&vbb->entry, &buffers);
-		}
 	}
 
 	handle_receive(vb, &buffers);
@@ -1297,7 +1313,7 @@
 	while (!list_empty(&buffers)) {
 		vbb = list_entry(buffers.next, struct vbb, entry);
 		list_del(&vbb->entry);
-		kmem_cache_free(buffer_cache, vbb);
+		kmem_cache_free(voicebus_vbb_cache, vbb);
 	}
 	return;
 }
@@ -1365,7 +1381,8 @@
 
 	if (unlikely((int_status &
 	    (TX_UNAVAILABLE_INTERRUPT|RX_UNAVAILABLE_INTERRUPT)) &&
-	    !test_bit(VOICEBUS_STOP, &vb->flags))) {
+	    !test_bit(VOICEBUS_STOP, &vb->flags) &&
+	    test_bit(VOICEBUS_NORMAL_MODE, &vb->flags))) {
 		schedule_work(&vb->underrun_work);
 		__vb_setctl(vb, SR_CSR5, int_status);
 	} else if (likely(int_status &
@@ -1422,12 +1439,6 @@
 }
 #endif
 
-static void vb_tasklet(unsigned long data)
-{
-	struct voicebus *vb = (struct voicebus *)data;
-	vb_deferred(vb);
-}
-
 /*!
  * \brief Initalize the voicebus interface.
  *
@@ -1462,7 +1473,6 @@
 	vb->min_tx_buffer_count = VOICEBUS_DEFAULT_LATENCY;
 
 	INIT_LIST_HEAD(&vb->tx_complete);
-	tasklet_init(&vb->tasklet, vb_tasklet, (unsigned long)vb);
 
 #if defined(CONFIG_VOICEBUS_TIMER)
 	init_timer(&vb->timer);
@@ -1672,7 +1682,7 @@
 	int res;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
-	buffer_cache = kmem_cache_create(THIS_MODULE->name,
+	voicebus_vbb_cache = kmem_cache_create(THIS_MODULE->name,
 					 sizeof(struct vbb), 0,
 #if defined(CONFIG_SLUB) && (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22))
 					 SLAB_HWCACHE_ALIGN |
@@ -1684,18 +1694,18 @@
 #endif
 #else
 #if (defined(DEBUG) && defined(CONFIG_SLAB_DEBUG))
-	buffer_cache = kmem_cache_create(THIS_MODULE->name,
+	voicebus_vbb_cache = kmem_cache_create(THIS_MODULE->name,
 					 sizeof(struct vbb), 0,
 					 SLAB_HWCACHE_ALIGN | SLAB_STORE_USER |
 					 SLAB_POISON | SLAB_DEBUG_FREE, NULL);
 #else
-	buffer_cache = kmem_cache_create(THIS_MODULE->name,
+	voicebus_vbb_cache = kmem_cache_create(THIS_MODULE->name,
 					 sizeof(struct vbb), 0,
 					 SLAB_HWCACHE_ALIGN, NULL);
 #endif
 #endif
 
-	if (NULL == buffer_cache) {
+	if (NULL == voicebus_vbb_cache) {
 		printk(KERN_ERR "%s: Failed to allocate buffer cache.\n",
 		       THIS_MODULE->name);
 		return -ENOMEM;
@@ -1715,7 +1725,7 @@
 
 static void __exit voicebus_module_cleanup(void)
 {
-	kmem_cache_destroy(buffer_cache);
+	kmem_cache_destroy(voicebus_vbb_cache);
 	WARN_ON(!list_empty(&binary_loader_list));
 }
 

Modified: linux/trunk/drivers/dahdi/voicebus/voicebus.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/voicebus.h?view=diff&rev=8123&r1=8122&r2=8123
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.h (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.h Fri Feb 26 10:40:44 2010
@@ -132,12 +132,17 @@
 #endif
 };
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+extern kmem_cache_t *voicebus_vbb_cache;
+#else
+extern struct kmem_cache *voicebus_vbb_cache;
+#endif
+
 int __voicebus_init(struct voicebus *vb, const char *board_name,
 		    int normal_mode);
 void voicebus_release(struct voicebus *vb);
 int voicebus_start(struct voicebus *vb);
 int voicebus_stop(struct voicebus *vb);
-void voicebus_free(struct voicebus *vb, struct vbb *vbb);
 int voicebus_transmit(struct voicebus *vb, struct vbb *vbb);
 int voicebus_set_minlatency(struct voicebus *vb, unsigned int milliseconds);
 int voicebus_current_latency(struct voicebus *vb);

Modified: linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c?view=diff&rev=8123&r1=8122&r2=8123
==============================================================================
--- linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c (original)
+++ linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c Fri Feb 26 10:40:44 2010
@@ -105,15 +105,20 @@
 	struct private_context *ctx;
 	const struct voicebus_operations *old;
 	void *old_drvdata;
+	int id;
 	might_sleep();
 	ctx = kzalloc(sizeof(struct private_context), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 	init_private_context(ctx);
 	ctx->vb = vb;
-	ret = __vpmadt032_start_load(
-			0, vb->pdev->vendor << 16 | vb->pdev->device,
-			&ctx->pvt);
+
+	if (0x8007 == vb->pdev->device || 0x8008 == vb->pdev->device)
+		id = vb->pdev->vendor << 16 | 0x2400;
+	else
+		id = vb->pdev->vendor << 16 | vb->pdev->device;
+
+	ret = __vpmadt032_start_load(0, id, &ctx->pvt);
 	if (ret)
 		goto error_exit;
 	old_drvdata = pci_get_drvdata(vb->pdev);

Modified: linux/trunk/drivers/dahdi/wctdm24xxp/Kbuild
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wctdm24xxp/Kbuild?view=diff&rev=8123&r1=8122&r2=8123
==============================================================================
--- linux/trunk/drivers/dahdi/wctdm24xxp/Kbuild (original)
+++ linux/trunk/drivers/dahdi/wctdm24xxp/Kbuild Fri Feb 26 10:40:44 2010
@@ -2,4 +2,4 @@
 
 EXTRA_CFLAGS += -I$(src)/.. -Wno-undef
 
-wctdm24xxp-objs := base.o 
+wctdm24xxp-objs := base.o xhfc.o

Modified: linux/trunk/drivers/dahdi/wctdm24xxp/base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wctdm24xxp/base.c?view=diff&rev=8123&r1=8122&r2=8123
==============================================================================
--- linux/trunk/drivers/dahdi/wctdm24xxp/base.c (original)
+++ linux/trunk/drivers/dahdi/wctdm24xxp/base.c Fri Feb 26 10:40:44 2010
@@ -3,6 +3,9 @@
  *
  * Written by Mark Spencer <markster at digium.com>
  * Support for TDM800P and VPM150M by Matthew Fredrickson <creslin at digium.com>
+ *
+ * Support for Hx8 by Andrew Kohlsmith <akohlsmith at mixdown.ca> and Matthew
+ * Fredrickson <creslin at digium.com>
  *
  * Copyright (C) 2005 - 2010 Digium, Inc.
  * All rights reserved.
@@ -34,6 +37,8 @@
 Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db
 */
 
+#define DEBUG
+
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -46,11 +51,13 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
+#include <linux/firmware.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
 #include <linux/semaphore.h>
 #else
 #include <asm/semaphore.h>
 #endif
+#include <linux/crc32.h>
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
 /* Define this if you would like to load the modules in parallel.  While this
@@ -68,6 +75,7 @@
 #include "proslic.h"
 
 #include "wctdm24xxp.h"
+#include "xhfc.h"
 
 #include "adt_lec.h"
 
@@ -187,10 +195,24 @@
 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 const struct wctdm_desc wcha80000 = { "HA8-0000", 0, 8 };
+static const struct wctdm_desc wchb80000 = { "HB8-0000", FLAG_EXPRESS, 8 };
+
+/**
+ * Returns true if the card is one of the Hybrid Digital Analog Cards.
+ */
+static inline bool is_hx8(const struct wctdm *wc)
+{
+	return (&wcha80000 == wc->desc) || (&wchb80000 == wc->desc);
+}
+
+static inline bool is_digital_span(const struct wctdm_span *wspan)
+{
+	return (wspan->span.linecompat > 0);
+}
 
 struct wctdm *ifaces[WC_MAX_IFACES];
-spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
+DECLARE_MUTEX(ifacelock);
 
 static void wctdm_release(struct wctdm *wc);
 
@@ -215,6 +237,7 @@
 static int ringdebounce = DEFAULT_RING_DEBOUNCE;
 static int fwringdetect = 0;
 static int latency = VOICEBUS_DEFAULT_LATENCY;
+static int forceload;
 
 #define MS_PER_HOOKCHECK	(1)
 #define NEONMWI_ON_DEBOUNCE	(100/MS_PER_HOOKCHECK)
@@ -291,7 +314,7 @@
 static inline int empty_slot(struct wctdm *wc, int card)
 {
 	int x;
-	for (x=0;x<USER_COMMANDS;x++) {
+	for (x = 0; x < USER_COMMANDS; x++) {
 		if (!wc->cmdq[card].cmds[x])
 			return x;
 	}
@@ -438,8 +461,7 @@
 		vpm->curecstate[i].nlp_type = vpm->options.vpmnlptype;
 		vpm->curecstate[i].nlp_threshold = vpm->options.vpmnlpthresh;
 		vpm->curecstate[i].nlp_max_suppress = vpm->options.vpmnlpmaxsupp;
-		vpm->curecstate[i].companding = (wc->span.deflaw == DAHDI_LAW_MULAW) ? ADT_COMP_ULAW : ADT_COMP_ALAW;
-
+		vpm->curecstate[i].companding = (wc->chans[i]->chan.span->deflaw == DAHDI_LAW_ALAW) ? ADT_COMP_ALAW : ADT_COMP_ULAW;
 		/* set_vpmadt032_chanconfig_from_state(&vpm->curecstate[i], &vpm->options, i, &chanconfig); !!! */
 		vpm->setchanconfig_from_state(vpm, i, &chanconfig);
 		if ((res = gpakConfigureChannel(vpm->dspid, i, tdmToTdm, &chanconfig, &cstatus))) {
@@ -485,6 +507,7 @@
 
 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;
@@ -496,6 +519,7 @@
 	if (test_bit(VPM150M_SPIRESET, &vpmadt032->control) || test_bit(VPM150M_HPIRESET, &vpmadt032->control)) {
 		if (debug & DEBUG_ECHOCAN)
 			dev_info(&wc->vb.pdev->dev, "HW Resetting VPMADT032...\n");
+		spin_lock_irqsave(&wc->reglock, flags);
 		for (x = 24; x < 28; x++) {
 			if (x == 24) {
 				if (test_and_clear_bit(VPM150M_SPIRESET, &vpmadt032->control))
@@ -507,6 +531,7 @@
 			writechunk[CMD_BYTE(x, 1, 0)] = 0;
 			writechunk[CMD_BYTE(x, 2, 0)] = 0x00;
 		}
+		spin_unlock_irqrestore(&wc->reglock, flags);
 		return;
 	}
 
@@ -603,39 +628,37 @@
 	ecval = ecval % EC_SIZE;
 #endif
 
- 	/* if a QRV card, map it to its first channel */  
- 	if ((wc->modtype[card] ==  MOD_TYPE_QRV) && (card & 3))
- 	{
- 		return;
- 	}
- 	if (wc->altcs[card])
- 		subaddr = 0;
- 
-
- 
+	/* QRV and BRI modules only use commands relating to the first channel */
+	if ((card & 0x03) && (wc->modtype[card] ==  MOD_TYPE_QRV)) {
+		return;
+	}
+
+	if (wc->altcs[card])
+		subaddr = 0;
+
 	/* Skip audio */
 	writechunk += 24;
 	spin_lock_irqsave(&wc->reglock, flags);
 	/* Search for something waiting to transmit */
 	if (pos) {
-		for (x=0;x<MAX_COMMANDS;x++) {
+		for (x = 0; x < MAX_COMMANDS; x++) {
 			if ((wc->cmdq[card].cmds[x] & (__CMD_RD | __CMD_WR)) && 
 			   !(wc->cmdq[card].cmds[x] & (__CMD_TX | __CMD_FIN))) {
 			   	curcmd = wc->cmdq[card].cmds[x];
-#if 0
-				dev_info(&wc->vb.pdev->dev, "Transmitting command '%08x' in slot %d\n", wc->cmdq[card].cmds[x], wc->txident);
-#endif			
 				wc->cmdq[card].cmds[x] |= (wc->txident << 24) | __CMD_TX;
 				break;
 			}
 		}
 	}
+
 	if (!curcmd) {
 		/* If nothing else, use filler */
 		if (wc->modtype[card] == MOD_TYPE_FXS)
 			curcmd = CMD_RD(LINE_STATE);
 		else if (wc->modtype[card] == MOD_TYPE_FXO)
 			curcmd = CMD_RD(12);
+		else if (wc->modtype[card] == MOD_TYPE_BRI)
+			curcmd = 0x101010;
 		else if (wc->modtype[card] == MOD_TYPE_QRV)
 			curcmd = CMD_RD(3);
 		else if (wc->modtype[card] == MOD_TYPE_VPM) {
@@ -649,13 +672,15 @@
 			curcmd = CMD_RD(0x1a0);
 		}
 	}
+
 	if (wc->modtype[card] == MOD_TYPE_FXS) {
- 		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = (1 << (subaddr));
+		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = (1 << (subaddr));
 		if (curcmd & __CMD_WR)
- 			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0x7f;
+			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0x7f;
 		else
- 			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x80 | ((curcmd >> 8) & 0x7f);
- 		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x80 | ((curcmd >> 8) & 0x7f);
+		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+
 	} else if (wc->modtype[card] == MOD_TYPE_FXO) {
 		static const int FXO_ADDRS[4] = { 0x00, 0x08, 0x04, 0x0c };
 		int idx = CMD_BYTE(card, 0, wc->altcs[card]);
@@ -663,48 +688,53 @@
 			writechunk[idx] = 0x20 | FXO_ADDRS[subaddr];
 		else
 			writechunk[idx] = 0x60 | FXO_ADDRS[subaddr];
- 		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff;
- 		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff;
+		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+
 	} else if (wc->modtype[card] == MOD_TYPE_FXSINIT) {
 		/* Special case, we initialize the FXS's into the three-byte command mode then
 		   switch to the regular mode.  To send it into thee byte mode, treat the path as
 		   6 two-byte commands and in the last one we initialize register 0 to 0x80. All modules
 		   read this as the command to switch to daisy chain mode and we're done.  */
- 		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
- 		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
+		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
+		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
 		if ((card & 0x1) == 0x1) 
- 			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x80;
+			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x80;
 		else
- 			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+
+	} else if (wc->modtype[card] == MOD_TYPE_BRI) {
+
+		if (unlikely((curcmd != 0x101010) && (curcmd & 0x1010) == 0x1010)) /* b400m CPLD */
+			writechunk[CMD_BYTE(card, 0, 0)] = 0x55;
+		else /* xhfc */
+			writechunk[CMD_BYTE(card, 0, 0)] = 0x10;
+		writechunk[CMD_BYTE(card, 1, 0)] = (curcmd >> 8) & 0xff;
+		writechunk[CMD_BYTE(card, 2, 0)] = curcmd & 0xff;
 	} else if (wc->modtype[card] == MOD_TYPE_VPM) {
 		if (curcmd & __CMD_WR)
- 			writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xc | ((curcmd >> 16) & 0x1);
+			writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xc | ((curcmd >> 16) & 0x1);
 		else
- 			writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xa | ((curcmd >> 16) & 0x1);
- 		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff;
- 		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
-	} else if (wc->modtype[card] == MOD_TYPE_VPM150M) {
-		;
- 	} else if (wc->modtype[card] == MOD_TYPE_QRV) {
+			writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xa | ((curcmd >> 16) & 0x1);
+		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff;
+		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+	} else if (wc->modtype[card] == MOD_TYPE_QRV) {
  
- 		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
- 		if (!curcmd)
- 		{
- 			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
- 			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
- 		}
- 		else
- 		{
- 			if (curcmd & __CMD_WR)
- 				writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x40 | ((curcmd >> 8) & 0x3f);
- 			else
- 				writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0xc0 | ((curcmd >> 8) & 0x3f);
- 			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
- 		}
+		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
+		if (!curcmd) {
+			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
+			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+		} else {
+			if (curcmd & __CMD_WR)
+				writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x40 | ((curcmd >> 8) & 0x3f);
+			else
+				writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0xc0 | ((curcmd >> 8) & 0x3f);
+			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+		}
 	} else if (wc->modtype[card] == MOD_TYPE_NONE) {
- 		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
- 		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
- 		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x10;
+		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x10;
+		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x10;
 	}
 #if 0
 	/* XXX */
@@ -715,10 +745,10 @@
 #if 0
 	/* XXX */
 	cmddesc++;
-#endif	
-}
-
-static inline void cmd_decipher_vpmadt032(struct wctdm *wc, unsigned char *readchunk)
+#endif
+}
+
+static inline void cmd_decipher_vpmadt032(struct wctdm *wc, const u8 *readchunk)
 {
 	unsigned long flags;
 	struct vpmadt032 *vpm = wc->vpmadt032;
@@ -747,6 +777,7 @@
 
 	/* Skip audio */
 	readchunk += 24;
+
 	/* Store result */
 	cmd->data = (0xff & readchunk[CMD_BYTE(25, 1, 0)]) << 8;
 	cmd->data |= readchunk[CMD_BYTE(25, 2, 0)];
@@ -757,26 +788,23 @@
 		cmd->desc |= __VPM150M_FIN;
 		complete(&cmd->complete);
 	}
-#if 0
-	// if (printk_ratelimit()) 
-		dev_info(&wc->vb.pdev->dev, "Received txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", cmd->txident, cmd->desc, cmd->address, cmd->data);
-#endif
-}
-
-static inline void cmd_decipher(struct wctdm *wc, u8 *readchunk, int card)
+}
+
+static inline void cmd_decipher(struct wctdm *wc, const u8 *readchunk, int card)
 {
 	unsigned long flags;
 	unsigned char ident;
 	int x;
 
-	/* if a QRV card, map it to its first channel */  
-	if ((wc->modtype[card] ==  MOD_TYPE_QRV) && (card & 3))
-	{
+	/* QRV and BRI modules only use commands relating to the first channel */
+	if ((card & 0x03) && (wc->modtype[card] ==  MOD_TYPE_QRV)) { /* || (wc->modtype[card] ==  MOD_TYPE_BRI))) { */
 		return;
 	}
+
 	/* Skip audio */
 	readchunk += 24;
 	spin_lock_irqsave(&wc->reglock, flags);
+
 	/* Search for any pending results */
 	for (x=0;x<MAX_COMMANDS;x++) {
 		if ((wc->cmdq[card].cmds[x] & (__CMD_RD | __CMD_WR)) && 
@@ -787,6 +815,11 @@
 				/* Store result */
 				wc->cmdq[card].cmds[x] |= readchunk[CMD_BYTE(card, 2, wc->altcs[card])];
 				wc->cmdq[card].cmds[x] |= __CMD_FIN;
+/*
+				if (card == 0 && wc->cmdq[card].cmds[x] & __CMD_RD) {
+					dev_info(&wc->vb.pdev->dev, "decifer: got response %02x\n", wc->cmdq[card].cmds[x] & 0xff);
+				}
+*/
 				if (wc->cmdq[card].cmds[x] & __CMD_WR) {
 					/* Go ahead and clear out writes since they need no acknowledgement */
 					wc->cmdq[card].cmds[x] = 0x00000000;
@@ -819,6 +852,8 @@
 			wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(5);	/* Hook/Ring state */
 		} else if (wc->modtype[card] == MOD_TYPE_QRV) {
 			wc->cmdq[card & 0xfc].cmds[USER_COMMANDS + 0] = CMD_RD(3);	/* COR/CTCSS state */
+		} else if (wc->modtype[card] == MOD_TYPE_BRI) {
+			wc->cmdq[card].cmds[USER_COMMANDS + 0] = wctdm_bri_checkisr(wc, card, 0);
 #ifdef VPM_SUPPORT
 		} else if (wc->modtype[card] == MOD_TYPE_VPM) {
 			wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(0xb9); /* DTMF interrupt */
@@ -836,6 +871,8 @@
 			wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(29);	/* Battery */
 		} else if (wc->modtype[card] == MOD_TYPE_QRV) {
 			wc->cmdq[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3);	/* Battery */
+		} else if (wc->modtype[card] == MOD_TYPE_BRI) {
+			wc->cmdq[card].cmds[USER_COMMANDS + 1] = wctdm_bri_checkisr(wc, card, 1);
 #ifdef VPM_SUPPORT
 		} else if (wc->modtype[card] == MOD_TYPE_VPM) {
 			wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(0xbd); /* DTMF interrupt */
@@ -853,8 +890,8 @@
 	int i;
 	register u8 *chanchunk;
 
-	for (i = 0; i < wc->cards; i += 4) {
-		chanchunk = &wc->chans[0 + i]->writechunk[0];
+	for (i = 0; i < wc->avchannels; i += 4) {
+		chanchunk = &wc->chans[0 + i]->chan.writechunk[0];
 		sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0];
 		sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1];
 		sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2];
@@ -864,7 +901,7 @@
 		sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6];
 		sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7];
 
-		chanchunk = &wc->chans[1 + i]->writechunk[0];
+		chanchunk = &wc->chans[1 + i]->chan.writechunk[0];
 		sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0];
 		sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1];
 		sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2];
@@ -874,7 +911,7 @@
 		sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6];
 		sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7];
 
-		chanchunk = &wc->chans[2 + i]->writechunk[0];
+		chanchunk = &wc->chans[2 + i]->chan.writechunk[0];
 		sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0];
 		sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1];
 		sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2];
@@ -884,7 +921,7 @@
 		sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6];
 		sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7];
 
-		chanchunk = &wc->chans[3 + i]->writechunk[0];
+		chanchunk = &wc->chans[3 + i]->chan.writechunk[0];
 		sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0];
 		sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1];
 		sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2];
@@ -899,30 +936,40 @@
 static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechunk)
 {
 	int x,y;
+	struct dahdi_span *s;
 
 	/* Calculate Transmission */
 	if (likely(wc->initialized)) {
-		dahdi_transmit(&wc->span);
+		for (x = 0; x < MAX_SPANS; x++) {
+			if (wc->spans[x]) {
+				s = &wc->spans[x]->span;
+				dahdi_transmit(s);
+			}
+		}
 		insert_tdm_data(wc, writechunk);
 	}
 
-	for (x=0;x<DAHDI_CHUNKSIZE;x++) {
+	for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
 		/* Send a sample, as a 32-bit word */
-		for (y=0;y < wc->cards;y++) {
-			if (!x) {
+
+		/* TODO: ABK: hmm, this was originally mods_per_board, but we
+		 * need to worry about all the active "voice" timeslots, since
+		 * BRI modules have a different number of TDM channels than
+		 * installed modules. */
+		for (y = 0; y < wc->avchannels; y++) {
+			if (!x && y < wc->mods_per_board) {
 				cmd_checkisr(wc, y);
 			}
 
-			if (x < 3)
+			if ((x < 3) && (y < wc->mods_per_board))
 				cmd_dequeue(wc, writechunk, y, x);
 		}
 		if (!x)
 			wc->blinktimer++;
 		if (wc->vpm100) {
-			for (y=24;y<28;y++) {
-				if (!x) {
+			for (y = NUM_MODULES; y < NUM_MODULES + NUM_EC; y++) {
+				if (!x)
 					cmd_checkisr(wc, y);
-				}
 				cmd_dequeue(wc, writechunk, y, x);
 			}
 #ifdef FANCY_ECHOCAN
@@ -939,7 +986,7 @@
 			writechunk[EFRAME_SIZE] = wc->ctlreg;
 			writechunk[EFRAME_SIZE + 1] = wc->txident++;
 
-			if ((wc->desc->ports == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_CARDS] == MOD_TYPE_NONE))) {
+			if ((wc->desc->ports == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_MODULES] == MOD_TYPE_NONE))) {
 				writechunk[EFRAME_SIZE + 2] = 0;
 				for (y = 0; y < 4; y++) {
 					if (wc->modtype[y] == MOD_TYPE_NONE)
@@ -958,11 +1005,11 @@
 	int hit=0;
 	int ret;
 
-	/* if a QRV card, use only its first channel */  
-	if (wc->modtype[card] ==  MOD_TYPE_QRV)
-	{
-		if (card & 3) return(0);
-	}
+	/* QRV and BRI cards are only addressed at their first "port" */
+	if ((card & 0x03) && ((wc->modtype[card] ==  MOD_TYPE_QRV) ||
+	    (wc->modtype[card] ==  MOD_TYPE_BRI)))
+		return 0;
+
 	do {
 		spin_lock_irqsave(&wc->reglock, flags);
 		hit = empty_slot(wc, card);
@@ -984,12 +1031,12 @@
 {
 	return wctdm_setreg_full(wc, card, addr, val, 1);
 }
-static inline int wctdm_setreg(struct wctdm *wc, int card, int addr, int val)
+inline int wctdm_setreg(struct wctdm *wc, int card, int addr, int val)
 {
 	return wctdm_setreg_full(wc, card, addr, val, 0);
 }
 
-static inline int wctdm_getreg(struct wctdm *wc, int card, int addr)
+inline int wctdm_getreg(struct wctdm *wc, int card, int addr)
 {
 	unsigned long flags;
 	int hit;
@@ -1028,14 +1075,15 @@
 	return ret;
 }
 
+
 static inline unsigned char wctdm_vpm_in(struct wctdm *wc, int unit, const unsigned int addr)
 {
-	return wctdm_getreg(wc, unit + NUM_CARDS, addr);
+	return wctdm_getreg(wc, unit + NUM_MODULES, addr);
 }
 
 static inline void wctdm_vpm_out(struct wctdm *wc, int unit, const unsigned int addr, const unsigned char val)
 {
-	wctdm_setreg(wc, unit + NUM_CARDS, addr, val);
+	wctdm_setreg(wc, unit + NUM_MODULES, addr, val);
 }
 
 /* TODO: this should go in the dahdi_voicebus module... */
@@ -1055,6 +1103,7 @@
 		list_move_tail(&cmd->node, &vpmadt032->pending_cmds);
 	}
 	spin_unlock_irqrestore(&vpmadt032->list_lock, flags);
+
 }
 
 static inline void cmd_retransmit(struct wctdm *wc)
@@ -1064,9 +1113,11 @@
 	/* Force retransmissions */
 	spin_lock_irqsave(&wc->reglock, flags);
 	for (x=0;x<MAX_COMMANDS;x++) {
-		for (y=0;y<wc->cards;y++) {
-			if (!(wc->cmdq[y].cmds[x] & __CMD_FIN))
-				wc->cmdq[y].cmds[x] &= ~(__CMD_TX | (0xff << 24));
+		for (y = 0; y < wc->mods_per_board; y++) {
+			if (wc->modtype[y] != MOD_TYPE_BRI) {
+				if (!(wc->cmdq[y].cmds[x] & __CMD_FIN))
+					wc->cmdq[y].cmds[x] &= ~(__CMD_TX | (0xff << 24));
+			}
 		}
 	}
 	spin_unlock_irqrestore(&wc->reglock, flags);
@@ -1085,8 +1136,8 @@
 	int i;
 	register u8 *chanchunk;
 
-	for (i = 0; i < wc->cards; i += 4) {
-		chanchunk = &wc->chans[0 + i]->readchunk[0];
+	for (i = 0; i < wc->avchannels; i += 4) {
+		chanchunk = &wc->chans[0 + i]->chan.readchunk[0];
 		chanchunk[0] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
 		chanchunk[1] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
 		chanchunk[2] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
@@ -1096,7 +1147,7 @@
 		chanchunk[6] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
 		chanchunk[7] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
 
-		chanchunk = &wc->chans[1 + i]->readchunk[0];
+		chanchunk = &wc->chans[1 + i]->chan.readchunk[0];
 		chanchunk[0] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
 		chanchunk[1] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
 		chanchunk[2] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
@@ -1106,7 +1157,7 @@
 		chanchunk[6] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
 		chanchunk[7] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
 
-		chanchunk = &wc->chans[2 + i]->readchunk[0];
+		chanchunk = &wc->chans[2 + i]->chan.readchunk[0];
 		chanchunk[0] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
 		chanchunk[1] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
 		chanchunk[2] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
@@ -1116,7 +1167,7 @@
 		chanchunk[6] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*6];
 		chanchunk[7] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*7];
 
-		chanchunk = &wc->chans[3 + i]->readchunk[0];
+		chanchunk = &wc->chans[3 + i]->chan.readchunk[0];
 		chanchunk[0] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*0];
 		chanchunk[1] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*1];
 		chanchunk[2] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*2];
@@ -1128,9 +1179,10 @@
 	}
 }
 
-static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk)
+static inline void wctdm_receiveprep(struct wctdm *wc, const u8 *readchunk)
 {
 	int x,y;
+	bool irqmiss = 0;
 	unsigned char expected;
 
 	if (unlikely(!is_good_frame(readchunk)))
@@ -1139,38 +1191,56 @@
 	if (likely(wc->initialized))
 		extract_tdm_data(wc, readchunk);
 
-	for (x=0;x<DAHDI_CHUNKSIZE;x++) {
+	for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
 		if (x < DAHDI_CHUNKSIZE - 1) {
 			expected = wc->rxident+1;
 			wc->rxident = readchunk[EFRAME_SIZE + 1];
 			if (wc->rxident != expected) {
-				wc->span.irqmisses++;
+				irqmiss = 1;
 				cmd_retransmit(wc);
 			}
 		}
-		for (y=0;y < wc->cards;y++) {
+		for (y = 0; y < wc->avchannels; y++) {
 			if (x < 3)
 				cmd_decipher(wc, readchunk, y);
 		}
 		if (wc->vpm100) {
-			for (y=NUM_CARDS;y < NUM_CARDS + NUM_EC; y++)
+			for (y = NUM_MODULES; y < NUM_MODULES + NUM_EC; y++)
 				cmd_decipher(wc, readchunk, y);
-		} else if (wc->vpmadt032) {
+		} else if (wc->vpmadt032)
 			cmd_decipher_vpmadt032(wc, readchunk);
-		}
 
 		readchunk += (EFRAME_SIZE + EFRAME_GAP);
 	}
+
 	/* XXX We're wasting 8 taps.  We should get closer :( */
 	if (likely(wc->initialized)) {
-		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);
-		}
-		dahdi_receive(&wc->span);
-	}
+		for (x = 0; x < wc->avchannels; x++) {
+			struct dahdi_chan *c = &wc->chans[x]->chan;
+			dahdi_ec_chunk(c, c->readchunk, c->writechunk);
+		}
+
+		for (x = 0; x < MAX_SPANS; x++) {
+			if (wc->spans[x]) {
+				struct dahdi_span *s = &wc->spans[x]->span;
+#if 1
+				/* Check for digital spans */
+				if (s->chanconfig == b400m_chanconfig) {
+					BUG_ON(!is_hx8(wc));
+					if (s->flags & DAHDI_FLAG_RUNNING)
+						b400m_dchan(s);
+
+				}
+#endif
+				dahdi_receive(s);
+				if (unlikely(irqmiss))
+					++s->irqmisses;
+			}
+		}
+	}
+
 	/* Wake up anyone sleeping to read/write a new register */
-	wake_up_interruptible(&wc->regq);
+	wake_up_interruptible_all(&wc->regq);
 }
 
 static int wait_access(struct wctdm *wc, int card)
@@ -1193,7 +1263,8 @@
 
 	 }
 
-    if(count > (MAX-1)) dev_notice(&wc->vb.pdev->dev, " ##### Loop error (%02x) #####\n", data);
+    if (count > (MAX-1))

[... 5425 lines stripped ...]



More information about the svn-commits mailing list