[svn-commits] sruffell: linux/trunk r8468 - in /linux/trunk/drivers/dahdi: voicebus/ wcte12xp/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sun Apr 4 11:15:02 CDT 2010


Author: sruffell
Date: Sun Apr  4 11:14:59 2010
New Revision: 8468

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8468
Log:
wcte12xp:  Poll the VPM and reset it if necessary.

When the transmit descriptor runs out completely, there (appears to be) a
chance for a random command to be sent that results in the VPMADT032 to no
longer respond, typically resulting in one way audio.  This change introduces
a poll of the VPM.  If it fails the poll, it will be bypassed temporarily
while the driver resets and reprograms it.  Also, the VPM is initially
programmed in the spanconfig callback instead of at driver load.  This moves
the potential for underruns until later in the boot process. DAHDI-573.

Modified:
    linux/trunk/drivers/dahdi/voicebus/GpakCust.c
    linux/trunk/drivers/dahdi/voicebus/GpakCust.h
    linux/trunk/drivers/dahdi/voicebus/voicebus.c
    linux/trunk/drivers/dahdi/wcte12xp/base.c
    linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h

Modified: linux/trunk/drivers/dahdi/voicebus/GpakCust.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/GpakCust.c?view=diff&rev=8468&r1=8467&r2=8468
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/GpakCust.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/GpakCust.c Sun Apr  4 11:14:59 2010
@@ -560,6 +560,47 @@
 }
 EXPORT_SYMBOL(vpmadt032_alloc);
 
+int vpmadt032_reset(struct vpmadt032 *vpm)
+{
+	int res;
+	gpakPingDspStat_t pingstatus;
+	u16 version;
+
+	might_sleep();
+
+	set_bit(VPM150M_HPIRESET, &vpm->control);
+	msleep(2000);
+	while (test_bit(VPM150M_HPIRESET, &vpm->control))
+		msleep(1);
+
+	/* Set us up to page 0 */
+	vpmadt032_setpage(vpm, 0);
+
+	res = vpmadtreg_loadfirmware(vpm->vb);
+	if (res) {
+		dev_info(&vpm->vb->pdev->dev, "Failed to load the firmware.\n");
+		return res;
+	}
+	vpm->curpage = -1;
+
+	set_bit(VPM150M_SWRESET, &vpm->control);
+	while (test_bit(VPM150M_SWRESET, &vpm->control))
+		msleep(1);
+
+	/* Set us up to page 0 */
+	pingstatus = gpakPingDsp(vpm->dspid, &version);
+	if (!pingstatus) {
+		vpm_info(vpm, "VPM present and operational "
+			"(Firmware version %x)\n", version);
+		vpm->version = version;
+		res = 0;
+	} else {
+		res = -EIO;
+	}
+	return res;
+}
+EXPORT_SYMBOL(vpmadt032_reset);
+
 int
 vpmadt032_init(struct vpmadt032 *vpm, struct voicebus *vb)
 {
@@ -597,9 +638,9 @@
 		dev_info(&vpm->vb->pdev->dev, "Passed\n");
 
 	set_bit(VPM150M_HPIRESET, &vpm->control);
-	msleep(2000);
 	while (test_bit(VPM150M_HPIRESET, &vpm->control))
 		msleep(1);
+	msleep(250);
 
 	/* Set us up to page 0 */
 	vpmadt032_setpage(vpm, 0);
@@ -613,9 +654,8 @@
 			vpmadt032_getreg(vpm, 0x1000, &reg);
 			if (reg != i) {
 				printk(KERN_CONT "VPMADT032 Failed address test\n");
-				goto failed_exit;
+				res = -EIO;
 			}
-
 		}
 	}
 
@@ -641,11 +681,11 @@
 	pingstatus = gpakPingDsp(vpm->dspid, &vpm->version);
 
 	if (!pingstatus) {
-		dev_info(&vpm->vb->pdev->dev,
-			 "Version of DSP is %x\n", vpm->version);
+		dev_info(&vb->pdev->dev, "VPM present and operational "
+			"(Firmware version %x)\n", vpm->version);
 	} else {
 		dev_notice(&vpm->vb->pdev->dev, "VPMADT032 Failed! Unable to ping the DSP (%d)!\n", pingstatus);
-		res = -1;
+		res = -EIO;
 		goto failed_exit;
 	}
 
@@ -661,6 +701,7 @@
 	return res;
 }
 EXPORT_SYMBOL(vpmadt032_init);
+
 
 void vpmadt032_get_default_parameters(struct GpakEcanParms *p)
 {
@@ -694,7 +735,9 @@
 	struct change_order *order;
 	LIST_HEAD(local_list);
 
-	BUG_ON(!vpm);
+	if (!vpm)
+		return;
+
 	BUG_ON(!vpm->wq);
 
 	destroy_workqueue(vpm->wq);

Modified: linux/trunk/drivers/dahdi/voicebus/GpakCust.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/GpakCust.h?view=diff&rev=8468&r1=8467&r2=8468
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/GpakCust.h (original)
+++ linux/trunk/drivers/dahdi/voicebus/GpakCust.h Sun Apr  4 11:14:59 2010
@@ -136,6 +136,7 @@
 
 char vpmadt032tone_to_zaptone(GpakToneCodes_t tone);
 int vpmadt032_init(struct vpmadt032 *vpm, struct voicebus *vb);
+int vpmadt032_reset(struct vpmadt032 *vpm);
 struct vpmadt032 *vpmadt032_alloc(struct vpmadt032_options *options,
 					const char *board_name);
 void vpmadt032_free(struct vpmadt032 *vpm);

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=8468&r1=8467&r2=8468
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.c Sun Apr  4 11:14:59 2010
@@ -1757,7 +1757,7 @@
 		spin_unlock(&loader_list_lock);
 		dev_info(&vb->pdev->dev, "Failed to find a registered "
 			 "loader after loading module.\n");
-		ret = -1;
+		ret = -ENODEV;
 	}
 	return ret;
 }

Modified: linux/trunk/drivers/dahdi/wcte12xp/base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wcte12xp/base.c?view=diff&rev=8468&r1=8467&r2=8468
==============================================================================
--- linux/trunk/drivers/dahdi/wcte12xp/base.c (original)
+++ linux/trunk/drivers/dahdi/wcte12xp/base.c Sun Apr  4 11:14:59 2010
@@ -960,26 +960,6 @@
 		(wc->spantype != TYPE_E1)) {
 		__t1xxp_set_clear(wc, chan->channo);
 	}
-	return 0;
-}
-
-static int t1xxp_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc)
-{
-	struct t1 *wc = span->pvt;
-
-	/* Do we want to SYNC on receive or not */
-	if (lc->sync) {
-		set_bit(7, &wc->ctlreg);
-		span->syncsrc = span->spanno;
-	} else {
-		clear_bit(7, &wc->ctlreg);
-		span->syncsrc = 0;
-	}
-
-	/* If already running, apply changes immediately */
-	if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags))
-		return t1xxp_startup(span);
-
 	return 0;
 }
 
@@ -1355,105 +1335,9 @@
 #endif
 }
 
-static int t1_software_init(struct t1 *wc)
-{
-	int x;
-	int num;
-	struct pci_dev *pdev = wc->vb.pdev;
-
-	/* Find position */
-	for (x = 0; x < ARRAY_SIZE(ifaces); ++x) {
-		if (ifaces[x] == wc) {
-			debug_printk(wc, 1, "software init for card %d\n", x);
-			break;
-		}
-	}
-
-	if (x == ARRAY_SIZE(ifaces))
-		return -1;
-
-	t4_serial_setup(wc);
-
-	num = x;
-	sprintf(wc->span.name, "WCT1/%d", num);
-	snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, num);
-	wc->span.manufacturer = "Digium";
-	set_span_devicetype(wc);
-
-	snprintf(wc->span.location, sizeof(wc->span.location) - 1,
-		"PCI Bus %02d Slot %02d", pdev->bus->number,
-		PCI_SLOT(pdev->devfn) + 1);
-
-	wc->span.owner = THIS_MODULE;
-	wc->span.spanconfig = t1xxp_spanconfig;
-	wc->span.chanconfig = t1xxp_chanconfig;
-	wc->span.irq = pdev->irq;
-	wc->span.startup = t1xxp_startup;
-	wc->span.shutdown = t1xxp_shutdown;
-	wc->span.rbsbits = t1xxp_rbsbits;
-	wc->span.maint = t1xxp_maint;
-	wc->span.open = t1xxp_open;
-	wc->span.close = t1xxp_close;
-	wc->span.ioctl = t1xxp_ioctl;
-#ifdef VPM_SUPPORT
-	if (vpmsupport)
-		wc->span.echocan_create = echocan_create;
-#endif
-
-	if (wc->spantype == TYPE_E1) {
-		if (unchannelized)
-			wc->span.channels = 32;
-		else
-			wc->span.channels = 31;
-		wc->span.spantype = "E1";
-		wc->span.linecompat = DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4;
-		wc->span.deflaw = DAHDI_LAW_ALAW;
-	} else {
-		wc->span.channels = 24;
-		wc->span.spantype = "T1";
-		wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF;
-		wc->span.deflaw = DAHDI_LAW_MULAW;
-	}
-	wc->span.chans = wc->chans;
-	set_bit(DAHDI_FLAGBIT_RBS, &wc->span.flags);
-	wc->span.pvt = wc;
-	init_waitqueue_head(&wc->span.maintq);
-	for (x = 0; x < wc->span.channels; x++) {
-		sprintf(wc->chans[x]->name, "WCT1/%d/%d", num, x + 1);
-		wc->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 | 
-				      DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_MTP2 |
-				      DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS |
-				      DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF;
-		wc->chans[x]->pvt = wc;
-		wc->chans[x]->chanpos = x + 1;
-	}
-	if (dahdi_register(&wc->span, 0)) {
-		t1_info(wc, "Unable to register span with DAHDI\n");
-		return -1;
-	}
-
-	set_bit(INITIALIZED, &wc->bit_flags);
-
-	return 0;
-}
-
-#if 0
-
-#ifdef VPM_SUPPORT
-static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr) 
-{
-		return t1_getreg_full(wc, addr, unit);
-}
-
-static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val) 
-{
-		return t1_setreg(wc, addr, val, unit);
-}
-
-#endif
-#endif
-
-static void setchanconfig_from_state(struct vpmadt032 *vpm, int channel, GpakChannelConfig_t *chanconfig)
+static void
+setchanconfig_from_state(struct vpmadt032 *vpm, int channel,
+			 GpakChannelConfig_t *chanconfig)
 {
 	const struct vpmadt032_options *options;
 	GpakEcanParms_t *p;
@@ -1496,11 +1380,175 @@
 		sizeof(chanconfig->EcanParametersB));
 }
 
+static int
+t1xxp_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc)
+{
+	struct vpmadt032_options options;
+	struct t1 *wc = span->pvt;
+	int res;
+
+#ifdef VPM_SUPPORT
+	if (!fatal_signal_pending(current) && vpmsupport) {
+		struct vpmadt032 *vpm;
+		memset(&options, 0, sizeof(options));
+		options.debug = debug;
+		options.vpmnlptype = vpmnlptype;
+		options.vpmnlpthresh = vpmnlpthresh;
+		options.vpmnlpmaxsupp = vpmnlpmaxsupp;
+		options.channels = (wc->spantype == TYPE_T1) ? 24 : 32;
+
+		wc->vpm_check = jiffies + HZ*600;
+		wc->vpmadt032 = vpmadt032_alloc(&options, wc->name);
+		if (!wc->vpmadt032)
+			return -ENOMEM;
+
+		vpm = wc->vpmadt032;
+		vpm->setchanconfig_from_state = setchanconfig_from_state;
+
+		res = vpmadt032_init(vpm, &wc->vb);
+		if (-ENODEV == res) {
+			wc->vpm_check = jiffies + HZ*600;
+			vpmadt032_free(vpm);
+			wc->vpmadt032 = NULL;
+		} else if (res) {
+			wc->vpm_check = jiffies + HZ/2;
+		} else {
+			config_vpmadt032(vpm, wc);
+
+			set_span_devicetype(wc);
+			/* turn on vpm (RX audio from vpm module) */
+			wc->ctlreg |= 0x10;
+			wc->vpm_check = HZ*5;
+			if (vpmtsisupport) {
+				debug_printk(wc, 1, "enabling VPM TSI pin\n");
+				/* turn on vpm timeslot interchange pin */
+				wc->ctlreg |= 0x01;
+			}
+		}
+	} else {
+		t1_info(wc, "VPM Support Disabled\n");
+		wc->vpmadt032 = NULL;
+	}
+#endif
+
+	/* Do we want to SYNC on receive or not */
+	if (lc->sync) {
+		set_bit(7, &wc->ctlreg);
+		span->syncsrc = span->spanno;
+	} else {
+		clear_bit(7, &wc->ctlreg);
+		span->syncsrc = 0;
+	}
+
+	/* If already running, apply changes immediately */
+	if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags))
+		return t1xxp_startup(span);
+
+	return 0;
+}
+
+
+static int t1_software_init(struct t1 *wc)
+{
+	int x;
+	int num;
+	struct pci_dev *pdev = wc->vb.pdev;
+
+	/* Find position */
+	for (x = 0; x < ARRAY_SIZE(ifaces); ++x) {
+		if (ifaces[x] == wc) {
+			debug_printk(wc, 1, "software init for card %d\n", x);
+			break;
+		}
+	}
+
+	if (x == ARRAY_SIZE(ifaces))
+		return -1;
+
+	t4_serial_setup(wc);
+
+	num = x;
+	sprintf(wc->span.name, "WCT1/%d", num);
+	snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, num);
+	wc->span.manufacturer = "Digium";
+	set_span_devicetype(wc);
+
+	snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+		"PCI Bus %02d Slot %02d", pdev->bus->number,
+		PCI_SLOT(pdev->devfn) + 1);
+
+	wc->span.owner = THIS_MODULE;
+	wc->span.spanconfig = t1xxp_spanconfig;
+	wc->span.chanconfig = t1xxp_chanconfig;
+	wc->span.irq = pdev->irq;
+	wc->span.startup = t1xxp_startup;
+	wc->span.shutdown = t1xxp_shutdown;
+	wc->span.rbsbits = t1xxp_rbsbits;
+	wc->span.maint = t1xxp_maint;
+	wc->span.open = t1xxp_open;
+	wc->span.close = t1xxp_close;
+	wc->span.ioctl = t1xxp_ioctl;
+#ifdef VPM_SUPPORT
+	if (vpmsupport)
+		wc->span.echocan_create = echocan_create;
+#endif
+
+	if (wc->spantype == TYPE_E1) {
+		if (unchannelized)
+			wc->span.channels = 32;
+		else
+			wc->span.channels = 31;
+		wc->span.spantype = "E1";
+		wc->span.linecompat = DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4;
+		wc->span.deflaw = DAHDI_LAW_ALAW;
+	} else {
+		wc->span.channels = 24;
+		wc->span.spantype = "T1";
+		wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF;
+		wc->span.deflaw = DAHDI_LAW_MULAW;
+	}
+	wc->span.chans = wc->chans;
+	set_bit(DAHDI_FLAGBIT_RBS, &wc->span.flags);
+	wc->span.pvt = wc;
+	init_waitqueue_head(&wc->span.maintq);
+	for (x = 0; x < wc->span.channels; x++) {
+		sprintf(wc->chans[x]->name, "WCT1/%d/%d", num, x + 1);
+		wc->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 | 
+				      DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_MTP2 |
+				      DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS |
+				      DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF;
+		wc->chans[x]->pvt = wc;
+		wc->chans[x]->chanpos = x + 1;
+	}
+	if (dahdi_register(&wc->span, 0)) {
+		t1_info(wc, "Unable to register span with DAHDI\n");
+		return -1;
+	}
+
+	set_bit(INITIALIZED, &wc->bit_flags);
+
+	return 0;
+}
+
+#if 0
+
+#ifdef VPM_SUPPORT
+static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr) 
+{
+		return t1_getreg_full(wc, addr, unit);
+}
+
+static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val) 
+{
+		return t1_setreg(wc, addr, val, unit);
+}
+
+#endif
+#endif
+
 static int t1_hardware_post_init(struct t1 *wc)
 {
-	struct vpmadt032_options options;
 	unsigned int reg;
-	int res;
 	int x;
 
 	/* T1 or E1 */
@@ -1532,43 +1580,6 @@
 
 	t1_setleds(wc, wc->ledstate);
 
-#ifdef VPM_SUPPORT
-	if (!fatal_signal_pending(current) && vpmsupport) {
-		memset(&options, 0, sizeof(options));
-		options.debug = debug;
-		options.vpmnlptype = vpmnlptype;
-		options.vpmnlpthresh = vpmnlpthresh;
-		options.vpmnlpmaxsupp = vpmnlpmaxsupp;
-		options.channels = (wc->spantype == TYPE_T1) ? 24 : 32;
-
-		wc->vpmadt032 = vpmadt032_alloc(&options, wc->name);
-		if (!wc->vpmadt032)
-			return -ENOMEM;
-
-		wc->vpmadt032->setchanconfig_from_state = setchanconfig_from_state;
-
-		res = vpmadt032_init(wc->vpmadt032, &wc->vb);
-		if (res) {
-			vpmadt032_free(wc->vpmadt032);
-			wc->vpmadt032=NULL;
-			return -EIO;
-		}
-
-		config_vpmadt032(wc->vpmadt032, wc);
-
-		set_span_devicetype(wc);
-		t1_info(wc, "VPM present and operational "
-			"(Firmware version %x)\n", wc->vpmadt032->version);
-		wc->ctlreg |= 0x10; /* turn on vpm (RX audio from vpm module) */
-		if (vpmtsisupport) {
-			debug_printk(wc, 1, "enabling VPM TSI pin\n");
-			wc->ctlreg |= 0x01; /* turn on vpm timeslot interchange pin */
-		}
-	} else {
-		t1_info(wc, "VPM Support Disabled\n");
-		wc->vpmadt032 = NULL;
-	}
-#endif
 	return 0;
 }
 
@@ -1802,15 +1813,12 @@
 		}
 
 		/* process the command queue */
-		for (y = 0; y < 7; y++) {
+		for (y = 0; y < 7; y++)
 			cmd_dequeue(wc, writechunk, x, y);
-		}
+
 #ifdef VPM_SUPPORT
-		if(likely(wc->vpmadt032)) {
-			spin_lock(&wc->reglock);
+		if (wc->vpmadt032)
 			cmd_dequeue_vpmadt032(wc, writechunk, x);
-			spin_unlock(&wc->reglock);
-		}
 #endif
 
 		if (x < DAHDI_CHUNKSIZE - 1) {
@@ -1912,26 +1920,97 @@
 {
 	struct t1 *wc = container_of(work, struct t1, timer_work);
 #endif
-	/* 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/10);
 }
 
-static void
-te12xp_timer(unsigned long data)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void vpm_check_func(void *data)
+{
+	struct t1 *wc = data;
+#else
+static void vpm_check_func(struct work_struct *work)
+{
+	struct t1 *wc = container_of(work, struct t1, vpm_check_work);
+#endif
+	int res;
+	u16 version;
+	unsigned long flags;
+
+	res = gpakPingDsp(wc->vpmadt032->dspid, &version);
+	if (!res) {
+		spin_lock_irqsave(&wc->reglock, flags);
+		wc->ctlreg |= 0x10;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		return;
+	}
+
+	/* Bypass the rx audio from the VPM module. */
+	spin_lock_irqsave(&wc->reglock, flags);
+	wc->ctlreg &= ~(0x10);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+	t1_info(wc, "VPMADT032 is non-responsive.  Resetting.\n");
+
+	res = vpmadt032_reset(wc->vpmadt032);
+	if (!res) {
+		config_vpmadt032(wc->vpmadt032, wc);
+		/* Looks like the reset went ok so we can put the VPM module
+		 * back in the TDM path. */
+		spin_lock_irqsave(&wc->reglock, flags);
+		wc->ctlreg |= 0x10;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		t1_info(wc, "VPMADT032 is reenabled.\n");
+	} else {
+		t1_info(wc, "Failed VPMADT032 reset. "
+			"VPMADT032 is disabled.\n");
+	}
+
+	return;
+}
+
+static void te12xp_timer(unsigned long data)
 {
 	struct t1 *wc = (struct t1 *)data;
+
+	if (unlikely(!test_bit(INITIALIZED, &wc->bit_flags)))
+		return;
+
 	queue_work(wc->wq, &wc->timer_work);
+
+	if (!wc->vpmadt032)
+		return;
+
+	if (time_after(wc->vpm_check, jiffies))
+		return;
+
+	/* We'll check the VPM module again in 5 seconds. */
+	wc->vpm_check = jiffies + 5*HZ;
+	queue_work(wc->vpmadt032->wq, &wc->vpm_check_work);
 	return;
+}
+
+static void t1_handle_error(struct voicebus *vb)
+{
+	struct t1 *wc = container_of(vb, struct t1, vb);
+	unsigned long flags;
+
+	if (wc->vpmadt032) {
+		/* Bypass the rx audio from the VPM module. */
+		spin_lock_irqsave(&wc->reglock, flags);
+		wc->ctlreg &= ~(0x10);
+		spin_unlock_irqrestore(&wc->reglock, flags);
+
+		queue_work(wc->vpmadt032->wq, &wc->vpm_check_work);
+	}
 }
 
 static const struct voicebus_operations voicebus_operations = {
 	.handle_receive = t1_handle_receive,
 	.handle_transmit = t1_handle_transmit,
+	.handle_error = t1_handle_error,
 };
 
 static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -1982,6 +2061,12 @@
 	INIT_WORK(&wc->timer_work, timer_work_func, wc);
 #	else
 	INIT_WORK(&wc->timer_work, timer_work_func);
+#	endif
+
+#	if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	INIT_WORK(&wc->vpm_check_work, vpm_check_func, wc);
+#	else
+	INIT_WORK(&wc->vpm_check_work, vpm_check_func);
 #	endif
 
 	snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", index);
@@ -2041,33 +2126,31 @@
 {
 	struct t1 *wc = pci_get_drvdata(pdev);
 #ifdef VPM_SUPPORT
-	unsigned long flags;
 	struct vpmadt032 *vpm = wc->vpmadt032;
 #endif
 	if (!wc)
 		return;
+
+	clear_bit(INITIALIZED, &wc->bit_flags);
+
+	del_timer_sync(&wc->timer);
+	flush_workqueue(wc->wq);
+#ifdef VPM_SUPPORT
+	if (vpm)
+		flush_workqueue(vpm->wq);
+#endif
+	del_timer_sync(&wc->timer);
 
 #ifdef VPM_SUPPORT
 	if(vpm) {
 		wc->vpmadt032 = NULL;
 		clear_bit(VPM150M_DTMFDETECT, &vpm->control);
 		clear_bit(VPM150M_ACTIVE, &vpm->control);
+		vpmadt032_free(vpm);
 	}
 #endif
-	clear_bit(INITIALIZED, &wc->bit_flags);
-	del_timer_sync(&wc->timer);
-	flush_workqueue(wc->wq);
-	del_timer_sync(&wc->timer);
 
 	voicebus_release(&wc->vb);
-
-#ifdef VPM_SUPPORT
-	if(vpm) {
-		spin_lock_irqsave(&wc->reglock, flags);
-		spin_unlock_irqrestore(&wc->reglock, flags);
-		vpmadt032_free(vpm);
-	}
-#endif
 	t1_release(wc);
 }
 

Modified: linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h?view=diff&rev=8468&r1=8467&r2=8468
==============================================================================
--- linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h (original)
+++ linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h Sun Apr  4 11:14:59 2010
@@ -126,6 +126,8 @@
 	atomic_t txints;
 	int vpm100;
 	struct vpmadt032 *vpmadt032;
+	unsigned long vpm_check;
+	struct work_struct vpm_check_work;
 	unsigned long dtmfactive;
 	unsigned long dtmfmask;
 	unsigned long dtmfmutemask;




More information about the svn-commits mailing list