[zaptel-commits] tzafrir: branch 1.2 r1966 - in /branches/1.2/xpp:
./ firmwares/ utils/
zaptel-commits at lists.digium.com
zaptel-commits at lists.digium.com
Thu Jan 25 03:48:34 MST 2007
Author: tzafrir
Date: Thu Jan 25 04:48:33 2007
New Revision: 1966
URL: http://svn.digium.com/view/zaptel?view=rev&rev=1966
Log:
* Xbus protocol version: 2.4 (Zaptel 1.2.12/1.4.0 had 2.3).
XPS Init scripts renamed accordingly.
* Performance improvements for multi-XPD (span) devices.
* Astribank BRI driver (in next commit).
* Changes under /proc:
- XBUS and XPD numbers have two digits.
- Every script wildcard should be replaced from XBUS-? to XBUS-[0-9]*
- Added /proc/xpp/XBUS-*/XPD-*/blink: echo 1 to start and 0 to stop.
* Several countries (South Africa, UAE, anybody else) require a shorter
ring delay. Adjust FXO reg 0x17 (23)'s bits 0:2 to 011.
* Use tasklets to move most of the interrupt PCM copying out of the interrupt.
* Debugfs-based code to dump data to userspace (used to debug BRI D channel).
* Pretend every 2.6.9 actually has later RHEL's typedefs.
* fpga_load supports /dev/bus/usb .
* Fixed physical order sorting in genzaptelconf.
Added:
branches/1.2/xpp/firmwares/FPGA_1141.hex (with props)
branches/1.2/xpp/firmwares/USB_1140.hex (with props)
branches/1.2/xpp/init_card_3_24
- copied unchanged from r1959, branches/1.2/xpp/init_card_3_23
branches/1.2/xpp/init_card_4_24
- copied, changed from r1959, branches/1.2/xpp/init_card_4_23
branches/1.2/xpp/init_card_6_24 (with props)
branches/1.2/xpp/init_card_7_24 (with props)
branches/1.2/xpp/xpp_log.h (with props)
Removed:
branches/1.2/xpp/init_card_3_23
branches/1.2/xpp/init_card_4_23
Modified:
branches/1.2/xpp/Makefile
branches/1.2/xpp/README.Astribank
branches/1.2/xpp/card_fxo.c
branches/1.2/xpp/card_fxs.c
branches/1.2/xpp/card_global.c
branches/1.2/xpp/firmwares/FPGA_1151.hex
branches/1.2/xpp/firmwares/FPGA_FXS.hex (contents, props changed)
branches/1.2/xpp/utils/Makefile
branches/1.2/xpp/utils/fpga_load.8
branches/1.2/xpp/utils/fpga_load.c
branches/1.2/xpp/utils/genzaptelconf
branches/1.2/xpp/utils/xpp_fxloader
branches/1.2/xpp/xbus-core.c
branches/1.2/xpp/xbus-core.h
branches/1.2/xpp/xdefs.h
branches/1.2/xpp/xpd.h
branches/1.2/xpp/xpp_usb.c
branches/1.2/xpp/xpp_zap.c
branches/1.2/xpp/xpp_zap.h
branches/1.2/xpp/xproto.c
branches/1.2/xpp/xproto.h
branches/1.2/xpp/zap_debug.c
branches/1.2/xpp/zap_debug.h
Modified: branches/1.2/xpp/Makefile
URL: http://svn.digium.com/view/zaptel/branches/1.2/xpp/Makefile?view=diff&rev=1966&r1=1965&r2=1966
==============================================================================
--- branches/1.2/xpp/Makefile (original)
+++ branches/1.2/xpp/Makefile Thu Jan 25 04:48:33 2007
@@ -1,15 +1,33 @@
-EXTRA_CFLAGS = -g3 -I$(SUBDIRS) -DDEBUG -DPOLL_DIGITAL_INPUTS -DWITH_ECHO_SUPPRESSION
+EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \
+ -g3 -I$(SUBDIRS) \
+ -DDEBUG \
+ -DPOLL_DIGITAL_INPUTS \
+ -DWITH_ECHO_SUPPRESSION \
+ -DPROTOCOL_DEBUG \
+ -DZAPTEL_EC_TYPEDEF \
+
+# Useful for Astribank-BRI debugging, and maybe more later on.
+# Requires debugfs support in the kernel.
+# -DXPP_DEBUGFS
+
+DRIVER_DIR = $(SUBDIRS)
obj-m += xpp.o xpd_fxs.o xpd_fxo.o
+
+HAS_BRISTUFF := $(shell cpp $(CPPFLAGS) -dM $(DRIVER_DIR)/zconfig.h | sed -n 's/^.*CONFIG_ZAPATA_BRI_DCHANS/y/p')
# Build only supported modules
ifneq (,$(filter y m,$(CONFIG_USB)))
obj-m += xpp_usb.o
endif
+ifneq (,$(HAS_BRISTUFF))
+obj-m += xpd_bri.o
+endif
xpp-y += xbus-core.o xpp_zap.o xproto.o card_global.o
xpd_fxs-y += card_fxs.o
xpd_fxo-y += card_fxo.o
+xpd_bri-y += card_bri.o
ctags:
ctags *.[ch]
Modified: branches/1.2/xpp/README.Astribank
URL: http://svn.digium.com/view/zaptel/branches/1.2/xpp/README.Astribank?view=diff&rev=1966&r1=1965&r2=1966
==============================================================================
--- branches/1.2/xpp/README.Astribank (original)
+++ branches/1.2/xpp/README.Astribank Thu Jan 25 04:48:33 2007
@@ -22,9 +22,10 @@
make -C xpp/utils
-In order to build the user space utilities, you will need the libusb-dev
-package on Debian (and derivatives like ubuntu) or libusb-devel on RedHat
+In order to build the user space utilities, you will need the libusb-dev
+package on Debian (and derivatives like ubuntu) or libusb-devel on RedHat
(and derivatives like Centox/Trixbox).
+
INSTALLATION:
""""""""""""
@@ -130,11 +131,54 @@
this will be the old value + 1.
+Firmware Loading with Hotplug:
+"""""""""""""""""""""""""""""
+The Hotplug framework was popular for hotplugging and usually also
+autoloading drivers. If it is used on your system, you'll see
+/etc/hotplug with many files under it. Hotplug will automatically load
+most relevant USB and PCI kernel modules by the relevant USB and PCI
+IDs. Again: if the framework is in place and the proper configuration
+files are in place, the firmware should be loaded automatically.
+
+In order to get hotplug to autoload the firmware into the Astribank,
+the configuration file xpp_fxloader.usermap and the script xpp_fxloader
+should be copied into /etc/hotplug/usb/ . This is done by 'make -C
+xpp/utils install' .
+
+xpp_fxloader.usermap includes a map of USB IDs and the command to run
+when they are encountered. It instructs hotplug to run the script
+xpp_fxloader from that directory. This is done by 'make -C
+xpp/utils install' .
+
+When xpp_fxloader is run without any parameters it assumes that it was
+run by the hotplug scripts. It will then check if the even is an "add"
+event (and not a "remove" event), and if so, install the required
+firmware file. It will be called twice, as after the load of the USB
+firmware the device will reenumerate itself and thus "unplug" and
+"replug" to load the FPGA firmware.
+
+
Firmware Loading with UDEV:
""""""""""""""""""""""""""
-Firmware loading with udev should work but is not installed
-automatically, yet. See the comments in the beginning of the script
-/etc/hotplug/usb/xpp_fxloader .
+The UDEV framework has replaced Hotplug in most recent systems. If you
+have a recent 2.6 system with no Hotplug and files under /etc/udev,
+chances are you ude udev. udev does quite a few nice things.
+Again: if the framework is in place and the proper configuration
+files are in place, the firmware should be loaded automatically.
+
+In order to get hotplug to autoload the firmware into the Astribank,
+the configuration file xpp.rules should be copied into /etc/udev/rules.d
+and the script xpp_fxloader should be copied into /etc/hotplug/usb/ .
+This is done by 'make -C xpp/utils install' .
+
+xpp.rules instructs udevd to run xpp_fxloader with the option udev and
+the USB ID when an Astribank is plugged and needs loading firmware.
+When xpp_fxloader is run with the option udev it assumes that it was
+run by udevd scripts. It will then install the required firmware file.
+It will be called twice, as after the load of the USB firmware the
+device will reenumerate itself and thus "unplug" and "replug" to load
+the FPGA firmware.
+
Loading The Modules:
"""""""""""""""""""
@@ -301,6 +345,47 @@
13 XPP_IN/0-12 FXOKS (In use)
14 XPP_IN/0-13 FXOKS (In use)
+Sample dialplan (extentions.conf) for all the above:
+
+[phones-zap]
+; 401 will dial to channel 1, 420, to zaptel channel 20, etc.
+exten => _4XX,1,Dial(ZAP/${EXTEN:1})
+
+[trunk-9]
+; Dial through the first FXO port availble.
+; This assumes that all FXO ports are in group 0 and all others are not,
+; as in the sample zapata.conf for 8FXS/8FXO below, and as is generated
+; by genzaptelconf by default.
+exten => 9.,Dial(Zap/g0/${EXTEN:1})
+
+[from-internal]
+; The context of FXS ports: analog phones.
+; They are allowed to dial to all other phones
+include => phones-zap
+; They are also allowed to call through the trunk:
+include => trunk-9
+
+[from-pstn]
+; Calls from the PSTN enter here. Redirect calls to an IVR
+; or a default extension in the s context here. In this case we
+; redirect calls to Zaptel channel 1:
+exten => s,1,Dial(Zap/1)
+
+[astribank-inputs]
+exten => s,1,Set(ZAP_CHAN=Cut(${CHANNEL},-,1))
+exten => s,n,Set(ZAP_CHAN=Cut(${ZAP_CHAN},/,2))
+; 11 is the number of the first input port. At least in the sample
+; configuration below.
+exten => s,n,Set(INPUT_NUM=Math(${ZAP_CHAN}-11))
+; The sample below just logs the signal.
+exten => s,n,NoOp(Got signal from input port number ${INPUT_NUM})
+; Alternatively:
+;exten => s,n,System(run something)
+
+; No. We did not forget the context astribank-outputs. Output
+; ports only get calls from the PBX. Thus they don't need a context
+; of their own.
+
/proc Interface
"""""""""""""""
Modified: branches/1.2/xpp/card_fxo.c
URL: http://svn.digium.com/view/zaptel/branches/1.2/xpp/card_fxo.c?view=diff&rev=1966&r1=1965&r2=1966
==============================================================================
--- branches/1.2/xpp/card_fxo.c (original)
+++ branches/1.2/xpp/card_fxo.c Thu Jan 25 04:48:33 2007
@@ -29,6 +29,7 @@
#include "xpp_zap.h"
#include "card_fxo.h"
#include "zap_debug.h"
+#include "xbus-core.h"
static const char rcsid[] = "$Id$";
@@ -65,7 +66,6 @@
/*---------------- FXO Protocol Commands ----------------------------------*/
static /* 0x0F */ DECLARE_CMD(FXO, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, lineno_t chan);
static /* 0x0F */ DECLARE_CMD(FXO, RING, lineno_t chan, bool on);
static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
@@ -152,7 +152,7 @@
for_each_line(xpd, i) {
if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
continue;
- if(IS_BLINKING(priv,i,color)) {
+ if(xpd->blink_mode || IS_BLINKING(priv,i,color)) {
// led state is toggled
if((timer_count % LED_BLINK_PERIOD) == 0) {
DBG("%s/%s/%d: ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
@@ -421,46 +421,41 @@
/* FIXME: based on data from from wctdm.h */
#include <wctdm.h>
-static const int echotune_reg[] = {30,45,46,47,58,49,50,51,52};
-union echotune {
- /* "coeff 0" is acim */
- unsigned char coeff[sizeof(echotune_reg)];
- struct wctdm_echo_coefs wctdm_struct;
-};
+/*
+ * The first register is the ACIM, the other are coefficient registers.
+ * We define the array size explicitly to track possible inconsistencies
+ * if the struct is modified.
+ */
+static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52};
static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
{
- union echotune echoregs;
- int i,ret;
-
- BUG_ON(!xpd);
- DBG("cmd: 0x%X, expecting: 0x%X, pos=%d.\n", cmd, WCTDM_SET_ECHOTUNE, pos);
+ int i,ret;
+ unsigned char echotune_data[ARRAY_SIZE(echotune_regs)];
+
+ BUG_ON(!xpd);
switch (cmd) {
case WCTDM_SET_ECHOTUNE:
DBG("-- Setting echo registers: \n");
/* first off: check if this span is fxs. If not: -EINVALID */
- if (copy_from_user(&echoregs.wctdm_struct,
- (struct wctdm_echo_coefs __user *)arg, sizeof(echoregs.wctdm_struct)))
+ if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data)))
return -EFAULT;
- /* Set the ACIM register */
- /* quick and dirty registers writing: */
- for (i=0; i<sizeof(echotune_reg); i++) {
- char buf[22];
- sprintf(buf, "%d WD %2X %2X",
- pos,echotune_reg[i],echoregs.coeff[i]
- );
- /* FIXME: code duplicated from proc_xpd_register_write */
- ret = handle_register_command(xpd, buf);
- if(ret < 0)
+ for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) {
+ DBG("Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]);
+ ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]);
+ if (ret < 0) {
+ NOTICE("%s/%s/%d: Couldn't write %0x02X to register %0x02X\n",
+ xpd->xbus->busname, xpd->xpdname, pos, echotune_data[i], echotune_regs[i]);
return ret;
+ }
msleep(1);
}
DBG("-- Set echo registers successfully\n");
-
break;
default:
+ DBG("%s/%s/%d: Unknown command 0x%X.\n", xpd->xbus->busname, xpd->xpdname, pos, cmd);
return -ENOTTY;
}
return 0;
@@ -471,6 +466,7 @@
/* 0x0F */ HOSTCMD(FXO, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
{
int ret = 0;
+ xframe_t *xframe;
xpacket_t *pack;
reg_cmd_t *reg_cmd;
@@ -478,7 +474,7 @@
DBG("NO XBUS\n");
return -EINVAL;
}
- XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
+ XFRAME_NEW(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
#if 0
DBG("%s/%s/%d: %c%c R%02X S%02X %02X %02X\n",
xbus->busname, xpd->xpdname, chipsel,
@@ -487,7 +483,6 @@
regnum, subreg, data_low, data_high);
#endif
reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
- pack->datalen = sizeof(*reg_cmd);
reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
REG_FIELD(reg_cmd, chipsel) = chipsel;
REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
@@ -496,7 +491,7 @@
REG_FIELD(reg_cmd, subreg) = subreg;
REG_FIELD(reg_cmd, data_low) = data_low;
REG_FIELD(reg_cmd, data_high) = data_high;
- ret = packet_send(xbus, pack);
+ ret = xframe_send(xbus, xframe);
return ret;
}
@@ -521,17 +516,6 @@
return ret;
}
-static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, lineno_t chan)
-{
- int ret = 0;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
- return ret;
-}
-
-
static /* 0x0F */ HOSTCMD(FXO, RING, lineno_t chan, bool on)
{
BUG_ON(!xbus);
@@ -557,7 +541,7 @@
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ __FUNCTION__, cmd->name, XPD_NUM(pack->addr));
return -EPROTO;
}
priv = xpd->priv;
@@ -567,9 +551,10 @@
for_each_line(xpd, i) {
if(IS_SET(sig_toggles, i)) {
if(!IS_SET(priv->battery, i)) {
- DBG("%s/%s/%d: battery is off. ignore false alarm.\n",
+ DBG("%s/%s/%d: SIG_CHANGED while battery is off.\n",
xbus->busname, xpd->xpdname, i);
- continue;
+ // FIXME: allow dialing without battery polling...
+ // continue;
}
mark_ring(xpd, i, IS_SET(sig_status, i), 1);
}
@@ -587,7 +572,7 @@
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ __FUNCTION__, cmd->name, XPD_NUM(pack->addr));
return -EPROTO;
}
spin_lock_irqsave(&xpd->lock, flags);
@@ -658,10 +643,8 @@
.RING = XPROTO_CALLER(FXO, RING),
.RELAY_OUT = XPROTO_CALLER(FXO, RELAY_OUT),
.XPD_STATE = XPROTO_CALLER(FXO, XPD_STATE),
- .CHAN_CID = XPROTO_CALLER(FXO, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
- .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
},
.packet_is_valid = fxo_packet_is_valid,
.packet_dump = fxo_packet_dump,
@@ -672,7 +655,7 @@
const xproto_entry_t *xe;
//DBG("\n");
- xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->content.opcode);
+ xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->opcode);
return xe != NULL;
}
@@ -896,7 +879,7 @@
int __init card_fxo_startup(void)
{
- INFO("%s\n", THIS_MODULE->name);
+ INFO("%s revision %s\n", THIS_MODULE->name, XPP_VERSION);
xproto_register(&PROTO_TABLE(FXO));
return 0;
}
@@ -909,6 +892,7 @@
MODULE_DESCRIPTION("XPP FXO Card Driver");
MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
MODULE_ALIAS_XPD(XPD_TYPE_FXO);
module_init(card_fxo_startup);
Modified: branches/1.2/xpp/card_fxs.c
URL: http://svn.digium.com/view/zaptel/branches/1.2/xpp/card_fxs.c?view=diff&rev=1966&r1=1965&r2=1966
==============================================================================
--- branches/1.2/xpp/card_fxs.c (original)
+++ branches/1.2/xpp/card_fxs.c Thu Jan 25 04:48:33 2007
@@ -29,6 +29,7 @@
#include "xpp_zap.h"
#include "card_fxo.h"
#include "zap_debug.h"
+#include "xbus-core.h"
static const char rcsid[] = "$Id$";
@@ -64,14 +65,13 @@
#define SLIC_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \
CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0)
#define SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH) \
- PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, (reg), 0, (dL), (dH))
+ CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH))
#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS)
/*---------------- FXS Protocol Commands ----------------------------------*/
static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, lineno_t chan);
static /* 0x0F */ DECLARE_CMD(FXS, RING, lineno_t chan, bool on);
static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
@@ -80,6 +80,7 @@
static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
#define PROC_REGISTER_FNAME "slics"
#define PROC_FXS_INFO_FNAME "fxs_info"
@@ -89,6 +90,8 @@
struct proc_dir_entry *fxs_info;
xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t found_fsk_pattern;
+ xpp_line_t msg_waiting;
int blinking[NUM_LEDS][CHANNELS_PERXPD];
};
@@ -137,7 +140,7 @@
/*
* pos can be:
* - A line number
- * - ALL_LINES
+ * - ALL_LINES. This is not valid anymore since 8-Jan-2007.
*/
static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
{
@@ -147,6 +150,7 @@
xbus_t *xbus;
BUG_ON(!xpd);
+ BUG_ON(chan == ALL_LINES);
xbus = xpd->xbus;
priv = xpd->priv;
which = which % NUM_LEDS;
@@ -186,7 +190,7 @@
for_each_line(xpd, i) {
if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
continue;
- if(IS_BLINKING(priv, i, color)) { // Blinking
+ if(xpd->blink_mode || IS_BLINKING(priv, i, color)) { // Blinking
// led state is toggled
if((timer_count % LED_BLINK_PERIOD) == 0) {
DBG("%s/%s/%d ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
@@ -206,6 +210,21 @@
}
}
}
+
+static int do_callerid(xbus_t *xbus, xpd_t *xpd, lineno_t chan)
+{
+ int ret = 0;
+ int i;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, FXS_LINE_CID);
+ for_each_line(xpd, i)
+ xpd->lasttxhook[i] = FXS_LINE_CID;
+ return ret;
+}
+
/*---------------- FXS: Methods -------------------------------------------*/
@@ -337,9 +356,11 @@
cur_chan->pvt = xpd;
cur_chan->sigcap = FXS_DEFAULT_SIGCAP;
}
- spin_lock_irqsave(&xpd->lock, flags);
- do_led(xpd, ALL_LINES, color, LED_OFF);
- spin_unlock_irqrestore(&xpd->lock, flags);
+ for_each_line(xpd, i) {
+ spin_lock_irqsave(&xpd->lock, flags);
+ do_led(xpd, i, color, LED_OFF);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ }
for_each_line(xpd, i) {
MARK_LED(priv, i, color, LED_ON);
msleep(50);
@@ -387,6 +408,8 @@
return ret;
}
ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+ if (!IS_SET(xpd->offhook, pos))
+ start_stop_vm_led(xbus, xpd, pos);
#if 0
switch(chan->sig) {
case ZT_SIG_EM:
@@ -403,7 +426,7 @@
case ZT_TXSIG_OFFHOOK:
if(xpd->ringing[pos]) {
BIT_SET(xpd->cid_on, pos);
- ret = CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos); // CALLER ID
+ ret = do_callerid(xpd->xbus, xpd, pos); // CALLER ID
}
xpd->ringing[pos] = 0;
#if 0
@@ -438,6 +461,107 @@
return ret;
}
+#ifdef VMWI_IOCTL
+/*
+ * Private ioctl()
+ * We don't need it now, since we detect vmwi via FSK patterns
+ */
+static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ struct FXS_priv_data *priv;
+ xbus_t *xbus;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+
+ if (pos < 0 || pos >= xpd->channels) {
+ NOTICE("%s/%s: Bad channel number %d in %s(), cmd=%u\n", xbus->busname, xpd->xpdname, pos, __FUNCTION__, cmd);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case _IOW(ZT_CODE, 60, int): /* message-waiting led control */
+ /* Digital inputs/outputs don't have VM leds */
+ if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
+ return 0;
+ if (arg)
+ BIT_SET(priv->msg_waiting, pos);
+ else
+ BIT_CLR(priv->msg_waiting, pos);
+ return 0;
+ }
+ return -ENOTTY;
+}
+#endif
+
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+{
+ int ret = 0;
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+
+ if (on) {
+ /* A write to register 0x40 will now turn on/off the VM led */
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
+ } else {
+ /* A write to register 0x40 will now turn on/off the ringer */
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
+ }
+
+ return (ret ? -EPROTO : 0);
+}
+
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
+{
+ bool on;
+
+ if (IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+ return;
+ on = IS_SET(((struct FXS_priv_data *)xpd->priv)->msg_waiting, pos);
+ DBG("%s/%s/%d %s\n", xbus->busname, xpd->xpdname, pos, (on)?"ON":"OFF");
+ set_vm_led_mode(xbus, xpd, pos, on);
+ do_chan_power(xbus, xpd, pos, on);
+ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x40, (on) ? 0x04 : 0x01);
+}
+
+static int FXS_chan_onhooktransfer(xbus_t *xbus, xpd_t *xpd, lineno_t chan, int millies)
+{
+ int ret = 0;
+
+ BUG_ON(!xpd);
+ BUG_ON(chan == ALL_CHANS);
+ DBG("%s/%s/%d: (%d millies)\n", xbus->busname, xpd->xpdname, chan, millies);
+ xpd->ohttimer[chan] = millies << 3;
+ xpd->idletxhookstate[chan] = FXS_LINE_CID; /* OHT mode when idle */
+ if (xpd->lasttxhook[chan] == FXS_LINE_ENABLED) {
+ /* Apply the change if appropriate */
+ ret = do_callerid(xpd->xbus, xpd, chan); // CALLER ID
+ }
+ start_stop_vm_led(xbus, xpd, chan);
+ return ret;
+}
+
/*
* INPUT polling is done via SLIC register 0x06 (same as LEDS):
* 7 6 5 4 3 2 1 0
@@ -460,6 +584,65 @@
}
}
+#ifndef VMWI_IOCTL
+/*
+ * Detect Voice Mail Waiting Indication
+ */
+static void detect_vmwi(xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ xbus_t *xbus;
+ static const byte FSK_COMMON_PATTERN[] = { 0xA8, 0x49, 0x22, 0x3B, 0x9F, 0xFF, 0x1F, 0xBB };
+ static const byte FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF };
+ static const byte FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F };
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ for_each_line(xpd, i) {
+ byte *writechunk = xpd->span.chans[i].writechunk;
+
+ if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i))
+ continue;
+#if 0
+ if(i == 0 && writechunk[0] != 0x7F) {
+ int j;
+
+ DBG("%s/%s/%d: MSG:", xbus->busname, xpd->xpdname, i);
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ printk(" %02X", writechunk[j]);
+ }
+ printk("\n");
+ }
+#endif
+ if(unlikely(memcmp(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE) == 0))
+ BIT_SET(priv->found_fsk_pattern, i);
+ else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
+ BIT_CLR(priv->found_fsk_pattern, i);
+ if(memcmp(writechunk, FSK_ON_PATTERN, ZT_CHUNKSIZE) == 0) {
+ DBG("%s/%s/%d: MSG WAITING ON\n", xbus->busname, xpd->xpdname, i);
+ BIT_SET(priv->msg_waiting, i);
+ start_stop_vm_led(xbus, xpd, i);
+ } else if(memcmp(writechunk, FSK_OFF_PATTERN, ZT_CHUNKSIZE) == 0) {
+ DBG("%s/%s/%d: MSG WAITING OFF\n", xbus->busname, xpd->xpdname, i);
+ BIT_CLR(priv->msg_waiting, i);
+ start_stop_vm_led(xbus, xpd, i);
+ } else {
+ int j;
+
+ NOTICE("%s/%s/%d: MSG WAITING Unexpected:", xbus->busname, xpd->xpdname, i);
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ printk(" %02X", writechunk[j]);
+ }
+ printk("\n");
+ }
+ }
+ }
+}
+#endif
+
static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
{
static int rate_limit = 0;
@@ -476,6 +659,10 @@
}
#endif
handle_fxs_leds(xpd);
+#ifndef VMWI_IOCTL
+ if(SPAN_REGISTERED(xpd))
+ detect_vmwi(xpd);
+#endif
return 0;
}
@@ -484,6 +671,7 @@
/* 0x0F */ HOSTCMD(FXS, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
{
int ret = 0;
+ xframe_t *xframe;
xpacket_t *pack;
reg_cmd_t *reg_cmd;
@@ -491,7 +679,7 @@
DBG("NO XBUS\n");
return -EINVAL;
}
- XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
+ XFRAME_NEW(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
#if 0
DBG("%s/%s/%d: %c%c R%02X S%02X %02X %02X\n",
xbus->busname, xpd->xpdname, chipsel,
@@ -500,7 +688,6 @@
regnum, subreg, data_low, data_high);
#endif
reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
- pack->datalen = sizeof(*reg_cmd);
reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
REG_FIELD(reg_cmd, chipsel) = chipsel;
REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
@@ -509,7 +696,7 @@
REG_FIELD(reg_cmd, subreg) = subreg;
REG_FIELD(reg_cmd, data_low) = data_low;
REG_FIELD(reg_cmd, data_high) = data_high;
- ret = packet_send(xbus, pack);
+ ret = xframe_send(xbus, xframe);
return ret;
}
@@ -538,31 +725,17 @@
return ret;
}
-static /* 0x0F */ HOSTCMD(FXS, CHAN_CID, lineno_t chan)
-{
- int ret = 0;
- int i;
+static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
+{
+ int ret = 0;
+ struct FXS_priv_data *priv;
+ enum fxs_state value = (on) ? 0x04 : 0x01;
BUG_ON(!xbus);
BUG_ON(!xpd);
- DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
- ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, FXS_LINE_CID);
- for_each_line(xpd, i)
- xpd->lasttxhook[i] = FXS_LINE_CID;
- return ret;
-}
-
-
-static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
-{
- int ret = 0;
- struct FXS_priv_data *priv;
- enum fxs_state value = (on) ? 0x04 : 0x01;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, chan, (on) ? "on" : "off");
priv = xpd->priv;
+ set_vm_led_mode(xbus, xpd, chan, 0);
do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, value);
xpd->lasttxhook[chan] = value;
@@ -605,10 +778,19 @@
BUG_ON(xpd->direction != TO_PHONE);
priv = xpd->priv;
DBG("%s/%s: (PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", xbus->busname, xpd->xpdname, sig_toggles, sig_status);
+#if 0
+ /*
+ * Not needed anymore. update_line_status() returns immediately
+ * if !SPAN_REGISTERED(). Now we maintain good status even if
+ * we are not registered.
+ *
+ * FIXME: Need to notify zaptel later (when registering).
+ */
if(!SPAN_REGISTERED(xpd)) {
NOTICE("%s: %s/%s is not registered. Skipping.\n", __FUNCTION__, xbus->busname, xpd->xpdname);
return -ENODEV;
}
+#endif
#if 0
Is this needed?
for_each_line(xpd, i) {
@@ -631,6 +813,7 @@
DBG("%s/%s/%d: ONHOOK\n", xbus->busname, xpd->xpdname, i);
MARK_LED(priv,i,LED_GREEN,LED_OFF);
update_line_status(xpd, i, 0);
+ start_stop_vm_led(xbus, xpd, i);
}
}
}
@@ -648,7 +831,7 @@
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ __FUNCTION__, cmd->name, XPD_NUM(pack->addr));
return -EPROTO;
}
spin_lock_irqsave(&xpd->lock, flags);
@@ -720,14 +903,16 @@
.card_zaptel_postregistration = FXS_card_zaptel_postregistration,
.card_hooksig = FXS_card_hooksig,
.card_tick = FXS_card_tick,
+ .chan_onhooktransfer = FXS_chan_onhooktransfer,
+#ifdef VMWI_IOCTL
+ .card_ioctl = FXS_card_ioctl,
+#endif
.RING = XPROTO_CALLER(FXS, RING),
.RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT),
.XPD_STATE = XPROTO_CALLER(FXS, XPD_STATE),
- .CHAN_CID = XPROTO_CALLER(FXS, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
- .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
},
.packet_is_valid = fxs_packet_is_valid,
.packet_dump = fxs_packet_dump,
@@ -738,7 +923,7 @@
const xproto_entry_t *xe;
// DBG("\n");
- xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->content.opcode);
+ xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->opcode);
return xe != NULL;
}
@@ -988,13 +1173,18 @@
int __init card_fxs_startup(void)
{
- INFO("%s\n", THIS_MODULE->name);
+ INFO("%s revision %s\n", THIS_MODULE->name, XPP_VERSION);
#ifdef POLL_DIGITAL_INPUTS
INFO("FEATURE: %s with DIGITAL INPUTS support (%s activated)\n",
THIS_MODULE->name, (poll_digital_inputs) ? "is" : "is not");
#else
INFO("FEATURE: %s without DIGITAL INPUTS support\n", THIS_MODULE->name);
#endif
+#ifdef VMWI_IOCTL
+ INFO("FEATURE: %s VMWI_IOCTL\n", THIS_MODULE->name);
+#else
+ INFO("FEATURE: %s NO VMWI_IOCTL\n", THIS_MODULE->name);
+#endif
xproto_register(&PROTO_TABLE(FXS));
return 0;
}
@@ -1007,6 +1197,7 @@
MODULE_DESCRIPTION("XPP FXS Card Driver");
MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
MODULE_ALIAS_XPD(XPD_TYPE_FXS);
module_init(card_fxs_startup);
Modified: branches/1.2/xpp/card_global.c
URL: http://svn.digium.com/view/zaptel/branches/1.2/xpp/card_global.c?view=diff&rev=1966&r1=1965&r2=1966
==============================================================================
--- branches/1.2/xpp/card_global.c (original)
+++ branches/1.2/xpp/card_global.c Thu Jan 25 04:48:33 2007
@@ -25,6 +25,7 @@
#include "xpp_zap.h"
#include "xproto.h"
#include "zap_debug.h"
+#include "xbus-core.h"
#include <linux/module.h>
static const char rcsid[] = "$Id$";
@@ -44,64 +45,23 @@
/* 0x04 */ HOSTCMD(GLOBAL, DESC_REQ, int xpd_num)
{
int ret = 0;
+ xframe_t *xframe;
xpacket_t *pack;
if(!xbus) {
DBG("NO XBUS\n");
return -EINVAL;
}
- XPACKET_NEW(pack, xbus, GLOBAL, DESC_REQ, xpd_num);
+ XFRAME_NEW(xframe, pack, xbus, GLOBAL, DESC_REQ, xpd_num);
DBG("on %s #%d\n", xbus->busname, xpd_num);
- ret = packet_send(xbus, pack);
+ ret = xframe_send(xbus, xframe);
XBUS_COUNTER(xbus, DESC_REQ)++;
return ret;
}
-/* 0x11 */ HOSTCMD(GLOBAL, PCM_WRITE, xpp_line_t lines, volatile byte *buf)
-{
- int ret = 0;
- xpacket_t *pack;
- byte *pcm;
- byte *start_pcm;
- int i;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= ~xpd->no_pcm;
- /*
- * FIXME: Workaround a bug in sync code of the Astribank.
- * Send dummy PCM for sync.
- */
- if(lines == 0)
- lines = BIT(0);
-
- XPACKET_NEW(pack, xbus, GLOBAL, PCM_WRITE, xpd->id);
- RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
- start_pcm = pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
- for_each_line(xpd, i) {
- if(IS_SET(lines, i)) {
- memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
- pcm += ZT_CHUNKSIZE;
- }
- buf += ZT_CHUNKSIZE;
- }
- /*
- * BRI: Software workaround for firmware limitation.
- * The BRI firmware count PCM channel number globally across subunits.
- */
- if(xpd->type == XPD_TYPE_BRI_NT || xpd->type == XPD_TYPE_BRI_TE) {
- lines = lines << (xpd->addr.subunit * 4);
- RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
- }
- pack->datalen = sizeof(xpp_line_t) + (pcm - start_pcm);
- packet_send(xbus, pack);
- XPD_COUNTER(xpd, PCM_WRITE)++;
- XBUS_COUNTER(xbus, PCM_WRITE)++;
- return ret;
-}
-
/* 0x19 */ HOSTCMD(GLOBAL, SYNC_SOURCE, bool setit, bool is_master)
{
+ xframe_t *xframe;
xpacket_t *pack;
byte mask = 0;
@@ -113,9 +73,9 @@
mask |= BIT(1);
DBG("SYNC_SOURCE %s setit=%s is_master=%s (mask=0x%X)\n",
xpd->xpdname, (setit)?"yes":"no", (is_master)?"yes":"no", mask);
- XPACKET_NEW(pack, xbus, GLOBAL, SYNC_SOURCE, xpd->id);
+ XFRAME_NEW(xframe, pack, xbus, GLOBAL, SYNC_SOURCE, xpd->id);
RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, mask) = mask;
- packet_send(xbus, pack);
+ xframe_send(xbus, xframe);
return 0;
}
@@ -177,11 +137,13 @@
unsigned long flags;
int i;
xpp_line_t old_lines = lines;
+ bool is_bri;
+ int subunit;
BUG_ON(!xbus);
if(!xpd) {
#if 0
- int xpd_num = XPD_NUM(pack->content.addr);
+ int xpd_num = XPD_NUM(pack->addr);
NOTICE("%s: received %s for non-existing xpd: %d\n",
__FUNCTION__, cmd->name, xpd_num);
#endif
@@ -189,44 +151,59 @@
}
// DBG("lines=0x%04X\n", lines);
- /*
- * BRI: Software workaround for firmware limitation.
- * The BRI firmware count PCM channel number globally across subunits.
- */
- if(xpd->type == XPD_TYPE_BRI_NT || xpd->type == XPD_TYPE_BRI_TE) {
- lines = (lines >> (xpd->addr.subunit * 4)) & 0x7;
- RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
- }
if(!pcm_valid(xpd, pack)) {
static int rate_limit;
if((rate_limit++ % 5001) == 0)
ERR("%s/%s: old_lines=0x%04X lines=0x%04X subunit=%d\n",
- xpd->xbus->busname, xpd->xpdname, old_lines, lines, xpd->addr.subunit);
+ xbus->busname, xpd->xpdname, old_lines, lines, xpd->addr.subunit);
return -EPROTO;
}
- spin_lock_irqsave(&xpd->lock, flags);
- if (xpd->timer_count & 1) {
- /* First part */
- r = readchunk = xpd->readchunk;
- } else {
- r = readchunk = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD;
- }
-
- /* Copy PCM and put each channel in its index */
- for_each_line(xpd, i) {
- if(IS_SET(lines, i)) {
- memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
- //memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
- pcm += ZT_CHUNKSIZE;
- }
- r += ZT_CHUNKSIZE;
- }
-
- XPD_COUNTER(xpd, PCM_READ)++;
- XBUS_COUNTER(xpd->xbus, PCM_READ)++;
- spin_unlock_irqrestore(&xpd->lock, flags);
- xpp_tick((unsigned long)xpd);
+ is_bri = (xpd->type == XPD_TYPE_BRI_NT || xpd->type == XPD_TYPE_BRI_TE);
+ do {
+ spin_lock_irqsave(&xpd->lock, flags);
+ if (xpd->timer_count & 1) {
+ /* First part */
+ r = readchunk = xpd->readchunk;
+ } else {
+ r = readchunk = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD;
+ }
+
+ /* Copy PCM and put each channel in its index */
+ for_each_line(xpd, i) {
+ if(IS_SET(lines, i)) {
+ memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
+ //memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
+ pcm += ZT_CHUNKSIZE;
+ }
+ r += ZT_CHUNKSIZE;
+ }
+
+ XPD_COUNTER(xpd, PCM_READ)++;
+ XBUS_COUNTER(xbus, PCM_READ)++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ got_pcm_from(xpd);
+
+ if (!is_bri)
+ break;
+ /*
+ * Handle BRI subunits
+ */
+ lines >>= SUBUNIT_PCM_SHIFT; /* B1, B2, D, E */
+ if (lines == 0)
+ break;
+ for(subunit = xpd->addr.subunit + 1; subunit < MAX_SUBUNIT; subunit++) {
+ xpd_t *tmp_xpd;
+
+ tmp_xpd = xpd_by_addr(xbus, xpd->addr.unit, subunit);
+ if(!tmp_xpd || !tmp_xpd->card_present)
+ continue;
+ xpd = tmp_xpd;
+ break;
+ }
+ if(subunit == MAX_SUBUNIT && printk_ratelimit())
+ NOTICE("%s/%s: subunit=%d lines=0x%04X\n", xbus->busname, xpd->xpdname, subunit, lines);
+ } while (1);
return 0;
}
@@ -238,14 +215,12 @@
BUG_ON(!xbus);
if(!xpd) {
- int xpd_num = XPD_NUM(pack->content.addr);
- NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
+ int xpd_num = XPD_NUM(pack->addr);
+ NOTICE("%s: received %s for non-existing xpd: addr=0x%02X\n", __FUNCTION__, cmd->name, xpd_num);
return -EPROTO;
}
DBG("%s/%s: SYNC_REPLY: 0x%X %s\n", xpd->xbus->busname, xpd->xpdname,
mask, (setit) ? "SET SYNC MASTER" : "");
- if(setit)
- sync_master_is(xpd);
return 0;
}
@@ -257,11 +232,13 @@
BUG_ON(!xbus);
if(!xpd) {
- int xpd_num = XPD_NUM(pack->content.addr);
- snprintf(xpdname, XPD_NAMELEN, "....#%d", xpd_num);
+ int xpd_num = XPD_NUM(pack->addr);
+ snprintf(xpdname, XPD_NAMELEN, "#%d", xpd_num);
} else {
snprintf(xpdname, XPD_NAMELEN, "%s", xpd->xpdname);
}
+ if(!printk_ratelimit())
+ return 0;
NOTICE("%s/%s: %s CODE = 0x%X\n", xbus->busname, xpdname, cmd->name, errorcode);
switch(errorcode) {
case 1:
@@ -298,7 +275,7 @@
const xproto_entry_t *xe;
//DBG("\n");
- xe = xproto_global_entry(pack->content.opcode);
+ xe = xproto_global_entry(pack->opcode);
return xe != NULL;
}
@@ -312,19 +289,27 @@
xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
int i;
int count = 0;
+ uint16_t good_len;
BUG_ON(!pack);
- BUG_ON(pack->content.opcode != XPROTO_NAME(GLOBAL, PCM_READ));
- for_each_line(xpd, i)
+ BUG_ON(pack->opcode != XPROTO_NAME(GLOBAL, PCM_READ));
+/*
+ * Don't use for_each_line(xpd, i) here because for BRI it will ignore the channels of the other
+ * xpd's in the same unit.
+ */
+ for (i = 0; i < CHANNELS_PERXPD; i++)
if(IS_SET(lines, i))
count++;
- if(pack->datalen != (sizeof(xpp_line_t) + count * 8)) {
+ /* FRAMES: include opcode in calculation */
+ good_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + count * 8;
+ if(pack->datalen != good_len) {
static int rate_limit = 0;
XPD_COUNTER(xpd, RECV_ERRORS)++;
if((rate_limit++ % 1000) <= 10) {
- ERR("%s/%s: BAD PCM REPLY: pack->datalen=%d, count=%d\n",
- xpd->xbus->busname, xpd->xpdname, pack->datalen, count);
+ ERR("%s/%s: BAD PCM REPLY: pack->datalen=%d (should be %d), count=%d\n",
+ xpd->xbus->busname, xpd->xpdname,
+ pack->datalen, good_len, count);
dump_packet("BAD PCM REPLY", pack, 1);
}
return 0;
Added: branches/1.2/xpp/firmwares/FPGA_1141.hex
URL: http://svn.digium.com/view/zaptel/branches/1.2/xpp/firmwares/FPGA_1141.hex?view=auto&rev=1966
==============================================================================
--- branches/1.2/xpp/firmwares/FPGA_1141.hex (added)
+++ branches/1.2/xpp/firmwares/FPGA_1141.hex Thu Jan 25 04:48:33 2007
@@ -1,0 +1,651 @@
+#
+# $Id: FPGA_1141.hex 3190 2007-01-24 13:25:57Z dima $
+#
+:020000040000FA
+:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF400060110A006AD6FF400060110A006AD6FF400060110A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B51111551111551111551115D
+:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200000000001AA1110000000000000000000000002552222552222F21F11211
[... 7871 lines stripped ...]
More information about the zaptel-commits
mailing list