summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2009-11-09 19:32:45 +0000
committerShaun Ruffell <sruffell@digium.com>2009-11-09 19:32:45 +0000
commitdcf556223a1443d56f633a83325e2a5950a3e724 (patch)
treea92357cac4314ed91b17ab60341e447d98c835df
parent0ee3bc8670599c0dfce468f33a4082818f9343db (diff)
Merged revisions 6699,6706,6714,6768,6771,6785,6812-6818,6821,6838,6928-6929,6941,6945-6946,6952,6981-6982,7003-7004,7008,7023,7027,7094-7097,7110,7117-7118,7125,7140,7147,7155,7194,7284,7293,7319,7437-7438,7445,7480,7486-7487,7512-7524,7527-7528,7534-7536 via svnmerge from
https://origsvn.digium.com/svn/dahdi/linux/trunk ........ r6699 | kpfleming | 2009-06-23 15:32:01 -0500 (Tue, 23 Jun 2009) | 3 lines Use the same mutex lock for channel allocation and license checking in dahdi_echocan_hpec, so that channel allocation won't happen while the license is being checked (or rechecked) ........ r6706 | sruffell | 2009-06-23 18:21:25 -0500 (Tue, 23 Jun 2009) | 1 line README: Minor corrections to the README. ........ r6714 | twilson | 2009-06-24 15:23:07 -0500 (Wed, 24 Jun 2009) | 1 line Remove unused torisa code from header ........ r6768 | sruffell | 2009-06-26 12:07:39 -0500 (Fri, 26 Jun 2009) | 1 line wct4xxp: Unmap the same size DMA window that was mapped. ........ r6771 | sruffell | 2009-06-26 12:22:45 -0500 (Fri, 26 Jun 2009) | 6 lines dahdi_dynamic: Release the dlock before calling accross modules. Resolves a hard lock due to a recursive spinlock grab at startup. Reported by: mapacheco (closes issue #15210) ........ r6785 | sruffell | 2009-06-28 23:47:26 -0500 (Sun, 28 Jun 2009) | 5 lines echocan: Properly keep the reference counts for the echocan modules. (closes issue #13504) (closes issue #15327) Reported by: sruffell, tzafrir ........ r6812 | tzafrir | 2009-07-02 14:25:54 -0500 (Thu, 02 Jul 2009) | 5 lines wcb4xxp: Don't assume we have 4 spans (ports). First part of extra hfcmulti drivers: the number of ports is still hardwired to 4, but just in a single place. ........ r6813 | tzafrir | 2009-07-02 14:34:05 -0500 (Thu, 02 Jul 2009) | 4 lines wcb4xxp: Extra bit macros that a needed for kernels < 2.6.24 Macros borrowed from xpp/ . ........ r6814 | tzafrir | 2009-07-02 14:42:25 -0500 (Thu, 02 Jul 2009) | 2 lines wcb4xxp: Adjust debug filter code to number of ports. ........ r6815 | tzafrir | 2009-07-02 14:52:14 -0500 (Thu, 02 Jul 2009) | 6 lines wcb4xxp: support for other HFC-xS cards (info, not code) This commit includes skeleton for the support of other HFC-[248]S-based cards. It still does not include all the different cases for different cards. ........ r6816 | tzafrir | 2009-07-02 14:59:44 -0500 (Thu, 02 Jul 2009) | 2 lines The B410P differs from other HFC-xS cards with respect to the EC unit ........ r6817 | tzafrir | 2009-07-02 15:07:36 -0500 (Thu, 02 Jul 2009) | 7 lines More B410P differences: Clock and NT/TE. * The B410P reads the NT/TE switches the other way around from other cards. * Its clock is also 1/2 of that of other cards, which causes wierd PCM on an unmodified driver. ........ r6818 | tzafrir | 2009-07-02 15:14:39 -0500 (Thu, 02 Jul 2009) | 4 lines wcb4xxp: Fix PCM handling for various cards. HFC-8S cards behave quite differently than HFC-4S cards here. ........ r6821 | tzafrir | 2009-07-02 15:18:59 -0500 (Thu, 02 Jul 2009) | 6 lines wcb4xxp: Fix LED handling in OpenVox cards (maybe also others) This commit adds extra functions to handle LEDs in the non-B410P cards. Only tested on OpenVox cards. OpenVox cards are known to have slightly different LEDs so this is likely to be slightly broken for others. ........ r6838 | sruffell | 2009-07-13 09:33:39 -0500 (Mon, 13 Jul 2009) | 1 line wctc4xxp: Remove deprecated DMA_xxBIT_MASK usage. ........ r6928 | sruffell | 2009-08-04 11:22:23 -0500 (Tue, 04 Aug 2009) | 1 line wcte12xp: Remove unused 'schluffen' declaration in wcte12xp.h ........ r6929 | sruffell | 2009-08-04 11:22:26 -0500 (Tue, 04 Aug 2009) | 4 lines wctdm24xxp: Eliminate 'variety' and 'type' members from 'struct wctdm'. struct wctdm can hold a pointer to struct wctdm_desc directly, and eliminate the need to copy members of wctdm_desc into wctdm. ........ r6941 | dbailey | 2009-08-05 09:40:45 -0500 (Wed, 05 Aug 2009) | 14 lines Change proslic linefeed register setting Insure that proslic linefeed register is not transitioned from Active to On-Hook Transmission while the channel is off-hook. Replaced magic numbers assigned to linefeed associated variables with more descriptive constants. (issue #15352) Reported by: alecdavis Patches: wctdm_prevent_ohttimer_click.diff3.txt uploaded by dbailey (license 819) Tested by: alecdavis, dbailey, vmikhelson ........ r6945 | sruffell | 2009-08-05 14:39:10 -0500 (Wed, 05 Aug 2009) | 6 lines wctdm24xxp, wctdm: Formatting changes. Update the lines affected by revision 6941. I'm taking every opportunity to move DAHDI closer to the kernel coding conventions short of just reformatting for the sake of reformatting. The majority of these changes are to bring the line lengths under 80 chars. ........ r6946 | sruffell | 2009-08-05 14:39:13 -0500 (Wed, 05 Aug 2009) | 1 line dahdi_dummy: Remove some trailing whitespace. ........ r6952 | sruffell | 2009-08-11 13:47:21 -0500 (Tue, 11 Aug 2009) | 3 lines wctdm24xxp: Remove unused members related to hardware DTMF detection. Not used anymore, so they are gone. ........ r6981 | sruffell | 2009-08-13 09:42:05 -0500 (Thu, 13 Aug 2009) | 1 line wctc4xxp: Remove flag member that is not used. ........ r6982 | sruffell | 2009-08-13 09:42:08 -0500 (Thu, 13 Aug 2009) | 1 line wctdm24xxp: Use the ARRAY_SIZE macro where appropriate. ........ r7003 | sruffell | 2009-08-13 19:46:26 -0500 (Thu, 13 Aug 2009) | 9 lines wctdm24xxp, wctdm: Detect if our hookstate has been set back to the initial state. Check if our hookstate has been set back to the initial state, typically the result of a chanconfig, and if so, if we're an FXO port, forget our current battery state. This allows the driver to determine and report again what the hook state of the port is. (related to issue #14577) (closes issue #15429) ........ r7004 | sruffell | 2009-08-13 19:46:28 -0500 (Thu, 13 Aug 2009) | 1 line dahdi-base: Add comment to explain why rxhooksig is reset on span start. ........ r7008 | sruffell | 2009-08-14 10:47:39 -0500 (Fri, 14 Aug 2009) | 11 lines wcfxo: Reset the DAA on module initialization. The X100p and clones will sometimes work and sometimes not depending on wether the DAA powers up in running state- this seems to be related to the power supply. This problem is caused by the driver not reseting the DAA and may be the source of a great many intermittent problems with this card. (closes issue #14232) Reported by: tallen8840 Patch by: tallen8840 Tested by: explidous, Flavio ........ r7023 | sruffell | 2009-08-17 09:07:06 -0500 (Mon, 17 Aug 2009) | 4 lines README: Update known issues section. Remove note about echocanceler reference counts, since that is fixed, and add a note about issue with KB1 when configured with more than 128 taps. ........ r7027 | seanbright | 2009-08-17 14:31:54 -0500 (Mon, 17 Aug 2009) | 7 lines Silence spurious warnings when trying to remove Zaptel directories during install. (closes issue #15479) Reported by: pprindeville Patches: dahdi-linux-rm.patch uploaded by pprindeville (license 347) ........ r7094 | sruffell | 2009-09-07 16:40:19 -0500 (Mon, 07 Sep 2009) | 4 lines wctdm24xxp: Remove a few more unneeded 'volatile' keywords. The writechunk and readchunk parameters are never accessed by hardware at the same time that the software is accessing them anymore. ........ r7095 | sruffell | 2009-09-07 16:40:22 -0500 (Mon, 07 Sep 2009) | 5 lines dahdi-base: Reduce the stack usage of dahdi_common_ioctl. Split the DAHDI_GETGAINS and DAHDI_SETGAINS ioctls into their own functions and dynamically allocate the 'struct dahdi_gains' structure to reduce the pressure on the stack. ........ r7096 | sruffell | 2009-09-07 16:40:25 -0500 (Mon, 07 Sep 2009) | 1 line dahdi-base: Prevent compilation if both EMPULSE and EMFLASH are defined. ........ r7097 | sruffell | 2009-09-07 16:40:29 -0500 (Mon, 07 Sep 2009) | 4 lines dahdi-base: Fix flag check in dahdi_rbs_sethook. As long as any of the flags were set, this check would have always passed. ........ r7110 | rmeyerriecks | 2009-09-14 15:30:24 -0500 (Mon, 14 Sep 2009) | 1 line Fixed issue where the clear channel flags were not being set at the appropriate time causing a channel re-configure to mis-set the last channel in each span ........ r7117 | dbailey | 2009-09-14 15:51:56 -0500 (Mon, 14 Sep 2009) | 17 lines Race condition in handling writes to proslic LINEFEED register (64) The wctdm24xxp driver has a problem where a VMWI IOCTL call followed immediately by a ONHOOKTRANSFER IOCTL call will cause the ONHOOK transfer request to be dropped. This occurs if the write to the proslic's LINEFEED register for the VMWI ICTL call is not completed when the ONHOOK transfer request IOCTL is processed. I also cleaned out some magic numbers used in setting the linefeed register. (closes issue #15875) Reported by: dbailey Patches: 15875-wctdm24xxp.diff uploaded by dbailey (license 819) Tested by: dbailey ........ r7118 | seanbright | 2009-09-14 16:10:38 -0500 (Mon, 14 Sep 2009) | 1 line Change zap -> dahdi. ........ r7125 | rmeyerriecks | 2009-09-15 09:59:06 -0500 (Tue, 15 Sep 2009) | 2 lines dahdi-base: Minor syntax change to meet style guidelines ........ r7140 | dbailey | 2009-09-15 15:50:45 -0500 (Tue, 15 Sep 2009) | 12 lines Change WCTDM SPI clock off state polarity and read timing Change the off state of the SPI clock to high and provide more time for data to settle out on SPI reads. (closes issue #15261) Reported by: alecdavis Patches: wctdm_spi_clocking.diff2.txt uploaded by alecdavis (license 585) Tested by: alecdavis, dbailey ........ r7147 | sruffell | 2009-09-16 13:19:00 -0500 (Wed, 16 Sep 2009) | 4 lines wct4xxp: Check the alarm state if we're debouncing a red alarm. This fixes a problem where if you set the alarmdebounce module parameter on gen2+ cards, you never detect when you go into red alarm. ........ r7155 | sruffell | 2009-09-21 10:24:36 -0500 (Mon, 21 Sep 2009) | 8 lines dahdi-base: dahdi_ioctl_[get|set]gains should return the res value. In function dahdi_ioctl_getgains() and dahdi_ioctl_setgains() return value assigned to res variable, but these function always return 0 which is an error. (closes issue #15916.) Patch by: ys ........ r7194 | dbailey | 2009-09-22 09:03:53 -0500 (Tue, 22 Sep 2009) | 12 lines wctdm: Add missing break A break was missing that caused DAHDI_ONHOOKTRANSFER ioctl call to fall into DAHDI_SETPOLARITY ioctl call. (issue #14261) Reported by: alecdavis Patches: wctdm_fix_ONHOOKTRANSFER.diff.txt uploaded by alecdavis (license 585) Tested by: alecdavis ........ r7284 | mattf | 2009-09-30 11:34:11 -0500 (Wed, 30 Sep 2009) | 1 line Update echocan API so it only uses channel offset in free routine ........ r7293 | tzafrir | 2009-09-30 13:09:42 -0500 (Wed, 30 Sep 2009) | 2 lines move the dev->bus_id fix from xpp to kernel.h: needed elsewhere ........ r7319 | sruffell | 2009-10-02 16:09:01 -0500 (Fri, 02 Oct 2009) | 1 line wcte12xp: The timer is called every 200ms, not every 100ms. Fix comment. ........ r7437 | sruffell | 2009-10-29 13:26:16 -0500 (Thu, 29 Oct 2009) | 10 lines dahdi-base: Do not allow jumps in system time to lock up the system w/core_timer Since dahdi coretimer uses the number of milliseconds that has actually passed to determine how many times to call dahdi_receive, it is possible that if the system time shifts after dahdi is started, that the system can appear to lock up while the core timer attempts to catch up. This change prevents soft lock ups under these conditions. This is brings the dahdi_dummy changes in r6933 into dahdi-base. (related to issue #15647) ........ r7438 | sruffell | 2009-10-29 13:26:17 -0500 (Thu, 29 Oct 2009) | 1 line wcte12xp, wctdm24xxp: VPMADT032 firmware update to 1.20. ........ r7445 | mspiceland | 2009-10-29 16:37:45 -0500 (Thu, 29 Oct 2009) | 3 lines Debounce alarms by default for wct4xxp per AT&T 54016. Also, the various alarm conditions can be debounced separately. ........ r7480 | sruffell | 2009-11-04 14:43:05 -0600 (Wed, 04 Nov 2009) | 4 lines voicebus: Increase the NLP converged threshold to 18. Brings in the change from r7065 that was on the team/sruffell/dahdi-linux-vpm119 branch. ........ r7486 | mspiceland | 2009-11-04 17:25:32 -0600 (Wed, 04 Nov 2009) | 9 lines Adding alarm debounce to single span driver (wcte12xp). Debounce yellow alarm also. In wcte12xp, change check alarm frequency to 100ms for better debounce granularity. Fix lines over 80 cols from last alarm debounce commit. ........ r7487 | mspiceland | 2009-11-04 17:28:21 -0600 (Wed, 04 Nov 2009) | 2 lines Remove commented out code block that was unintentionally left in. ........ r7512 | sruffell | 2009-11-06 18:35:38 -0600 (Fri, 06 Nov 2009) | 1 line wcte12xp: Remove unused flag member and make const the t1_descs. ........ r7513 | sruffell | 2009-11-06 18:35:38 -0600 (Fri, 06 Nov 2009) | 4 lines voicebus: Remove the VB_PRINTK macro. Unnecessarily duplicates the dev_xxx macros. Also removes the need for the board_name member from struct voicebus. ........ r7514 | sruffell | 2009-11-06 18:35:39 -0600 (Fri, 06 Nov 2009) | 4 lines voicebus: Remove sdi member from 'struct voicebus' This is only used during startup so we don't need to carry it around in the structure at all times. ........ r7515 | sruffell | 2009-11-06 18:35:40 -0600 (Fri, 06 Nov 2009) | 1 line voicebus: Set the DMA_BIT_MASK ........ r7516 | sruffell | 2009-11-06 18:35:40 -0600 (Fri, 06 Nov 2009) | 1 line voicebus: Use DAHDI_IRQ_SHARED instead of defining our own. ........ r7517 | sruffell | 2009-11-06 18:35:40 -0600 (Fri, 06 Nov 2009) | 24 lines voicebus: Send 'idle' buffers when the transmit descriptor underruns. Previously, when the host system fails to service the interrupt in a timely fashion, the transmit descriptor ring for the voicebus card would "go empty" since the interface wouldn't have another descriptor to read in. The driver only knows that it went empty, not how far behind it actually was. Therefore, the driver could just increase the latency by a millisecond and keep going waiting for another bump. Additionally, when the transmit descriptor actually goes empty, there are some cases where an in process SPI transaction to one of the modules is interrupted, which may result in corrupted module register writes on rare occassions. This now makes it possible for the voicebus drivers to coexist with some devices that periodically lock interrupts for longer than 25ms. Before this patch, the latency would constantly increase until either the modules received a corrupted frame. This patch preconfigures all the receive descriptors to send an "idle" packet that will be transmitted to the onboard modules when the host doesn't service the interrupt within (latency - 2)ms. There are now two kinds of underruns, softunderuns where the driver can detect that these idlebuffers have made it to the TX FIFO, and the normal hard underrun where the part signals a transmit descriptor unavailable interrupt. DAHDI-278. ........ r7518 | sruffell | 2009-11-06 18:35:41 -0600 (Fri, 06 Nov 2009) | 7 lines voicebus: Add function to lock the latency. Now that increases in the latency produce less undefined behavior on the SPI busses, provide an interface for client drivers to inform the voicebus library to not increase the latency if underruns are detected. This can speed up loads of the driver since latency bumps do not trigger a restart of the driver initialization. DAHDI-278. ........ r7519 | sruffell | 2009-11-06 18:35:42 -0600 (Fri, 06 Nov 2009) | 4 lines wcte12xp: Lock latency when loading No longer need to restart board initialization if the latency would have increased during initialization. DAHDI-278. ........ r7520 | sruffell | 2009-11-06 18:35:42 -0600 (Fri, 06 Nov 2009) | 4 lines wctdm24xxp: Lock latency when loading We no longer need to retry board initialization if the latency would have increased during the initialization. DAHDI-278 ........ r7521 | sruffell | 2009-11-06 18:35:43 -0600 (Fri, 06 Nov 2009) | 4 lines voicebus, wctdm24xxp, wcte12xp: Move a print out of the interrupt handler. This can be handled just as well in process context and printing to a serial console from the interrupt handler has the potential to cause long latencies. ........ r7522 | sruffell | 2009-11-06 18:35:44 -0600 (Fri, 06 Nov 2009) | 5 lines voicebus: Add optional sysfs entry for reading a boards current latency. This is off by default since it hasn't been tested on a full range of kernels, but can be useful for quickly seeing differences for latencies on different cards installed in the system. ........ r7523 | sruffell | 2009-11-06 18:35:44 -0600 (Fri, 06 Nov 2009) | 1 line voicebus: Remove 'assert' macros and use BUG_ON/WARN_ON directly. ........ r7524 | sruffell | 2009-11-06 18:35:45 -0600 (Fri, 06 Nov 2009) | 1 line voicebus: Be just a little more graceful if we cannot grab our interrupt line. ........ r7527 | sruffell | 2009-11-06 18:58:03 -0600 (Fri, 06 Nov 2009) | 1 line wcte12xp: Fix up some continued strings. ........ r7528 | sruffell | 2009-11-06 18:58:03 -0600 (Fri, 06 Nov 2009) | 1 line wct4xxp: Fix up some continued strings. ........ r7534 | sruffell | 2009-11-09 12:02:40 -0600 (Mon, 09 Nov 2009) | 1 line wct4xxp: Only print the new debounce messages when debug is set. ........ r7535 | sruffell | 2009-11-09 12:02:41 -0600 (Mon, 09 Nov 2009) | 1 line wcte12xp: Only print the new debounce messages when debug is set. ........ r7536 | sruffell | 2009-11-09 12:11:06 -0600 (Mon, 09 Nov 2009) | 4 lines wcte12xp: use the dev_xxx macro for the debounce messages. We want to know which device is reporting the debounce when there are more than one card in the system. ........ git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/branches/2.2@7539 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-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 */