summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-07-06 13:47:05 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-07-06 13:47:05 +0000
commit39a1812c1ef76b6a792f00087f1e507616bbbb25 (patch)
treee50633c999779c514ef16f4a2ce7a70fc7511c9e /xpp/xpp_zap.c
parent70ef1183eba2d2fe4f00668fd3438b7f1c842c94 (diff)
Tons of updates to the Astribank (xpp) driver:
* xpd_fxo.ko (FXO span) is now operational * Remove obsolete .inc initialization files (we use user-space init) * Added an install target to the utils dir. * Updated README.Astribank accordingly. * Using RBS signalling, as caller ID did not work well otherwise. * Better handling of USB protocol errors. * Fixed some procfs-related races. * per-card-module ioctls. * fxotune support. * opermode support (set through /etc/default/zaptel for now) * Userspace initialization script can also read registers. * Power calibration works (and implemented in perl) * some fine-tuning to the regster initialization parameters. * Leds turn on before registration and turn off after it. git-svn-id: http://svn.digium.com/svn/zaptel/trunk@1204 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c320
1 files changed, 135 insertions, 185 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index 4c8d3e9..4209fda 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -40,7 +40,7 @@
#include <linux/proc_fs.h>
#ifdef STANDALONE_ZAPATA
-#include "zaptel.h"
+#include "../zaptel.h"
#else
#include <zaptel/zaptel.h>
#endif
@@ -69,25 +69,20 @@ static struct timer_list xpp_timer;
static xpd_t *sync_master = NULL; // Start with host based sync
static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
-struct workqueue_struct *xpp_worker = NULL;
-
-static LIST_HEAD(xpd_list);
DEF_PARM(int, print_dbg, 0, "Print DBG statements");
DEF_PARM(int, max_queue_len, MAX_QUEUE_LEN, "Maximum Queue Length.");
-DEF_PARM(int, ignore_xpds, 0, "a bitmask of xpd numbers to ignore");
-DEF_PARM(int, xbus_err_disable_bus, 1000, "Number of errors needed to disable bus"); // FIXME: unused now.
-DEF_PARM(ulong, pcm_gen, 0, "a bitmask of line numbers for hardware tone generator");
DEF_PARM(bool, have_sync_bus, 0, "True if all Astribank(TM) devices are connected via a sync-cable");
DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)");
-DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd");
-
#include "zap_debug.h"
+#ifdef XPP_EC_CHUNK
+#include "echo_supress/ec_xpp.h"
+#endif
-static int xpd_zaptel_register(xpd_t *xpd);
-static int xpd_zaptel_unregister(xpd_t *xpd);
+static int zaptel_register_xpd(xpd_t *xpd);
+static int zaptel_unregister_xpd(xpd_t *xpd);
static void xpp_ring_generate(xpd_t *xpd);
static void xpp_transmitprep(xpd_t *xpd);
static void xpp_receiveprep(xpd_t *xpd);
@@ -207,7 +202,10 @@ static void xpd_free(xpd_t *xpd)
if(!xpd)
return;
xbus = xpd->xbus;
+ if(!xbus)
+ return;
DBG("%s/%s\n", xbus->busname, xpd->xpdname);
+ xbus_unregister_xpd(xbus, xpd);
#ifdef CONFIG_PROC_FS
if(xpd->proc_xpd_dir) {
if(xpd->proc_xpd_summary) {
@@ -227,23 +225,42 @@ static void xpd_free(xpd_t *xpd)
#endif
if(xpd->writechunk)
kfree((void *)xpd->writechunk);
+ xpd->writechunk = NULL;
if(xpd->xproto)
xproto_put(xpd->xproto);
+ xpd->xproto = NULL;
kfree(xpd);
}
/*------------------------- XPD Management -------------------------*/
+#define REV(x,y) (10 * (x) + (y))
+static byte good_revs[] = {
+ REV(1,9),
+ REV(2,0),
+};
+#undef REV
+
+static bool good_rev(byte rev)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(good_revs); i++) {
+ if(good_revs[i] == rev)
+ return 1;
+ }
+ return 0;
+}
+
/*
* Synchronous part of XPD detection.
- * Called from xpp_worker workqueue.
+ * Called from xbus_poll()
*/
-void card_detected(void *data)
+void card_detected(struct card_desc_struct *card_desc)
{
- struct card_desc_struct *card_desc = (struct card_desc_struct *)data;
xbus_t *xbus;
- xpd_t *xpd;
+ xpd_t *xpd = NULL;
int xpd_num;
byte type;
byte rev;
@@ -254,16 +271,24 @@ void card_detected(void *data)
BUG_ON(!card_desc);
BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
xbus = card_desc->xbus;
- xpd_num = card_desc->xpd_num;
+ xpd_num = xpd_addr2num(&card_desc->xpd_addr);
type = card_desc->type;
rev = card_desc->rev;
BUG_ON(!xbus);
- DBG("%s: xpd_num=%d type=%d rev=%d\n", xbus->busname, xpd_num, type, rev);
+ if(!good_rev(rev)) {
+ NOTICE("%s: New XPD #%d (%d-%d) type=%d has bad firmware revision %d.%d\n", xbus->busname,
+ xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
+ type, rev / 10, rev % 10);
+ goto err;
+ }
+ INFO("%s: New XPD #%d (%d-%d) type=%d Revision %d.%d\n", xbus->busname,
+ xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
+ type, rev / 10, rev % 10);
xpd = xpd_of(xbus, xpd_num);
if(xpd) {
if(type == XPD_TYPE_NOMODULE) {
NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
- xpd_disconnect(xpd);
+ BUG();
goto out;
}
NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
@@ -285,13 +310,14 @@ void card_detected(void *data)
NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
goto err;
}
+ xpd->addr = card_desc->xpd_addr;
/* For USB-1 disable some channels */
if(xbus->max_packet_size < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
xpp_line_t no_pcm;
no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
- xpd->no_pcm = no_pcm & xpd->enabled_chans;
+ xpd->no_pcm = no_pcm;
NOTICE("%s: max packet size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
xbus->busname, xbus->max_packet_size, xpd->no_pcm);
}
@@ -308,28 +334,28 @@ void card_detected(void *data)
ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
goto err;
}
+ xpd->proc_xpd_summary->owner = THIS_MODULE;
xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
if (!xpd->proc_xpd_ztregister) {
ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
goto err;
}
+ xpd->proc_xpd_ztregister->owner = THIS_MODULE;
xpd->proc_xpd_ztregister->data = xpd;
xpd->proc_xpd_ztregister->read_proc = proc_xpd_ztregister_read;
xpd->proc_xpd_ztregister->write_proc = proc_xpd_ztregister_write;
#endif
+ xbus_register_xpd(xbus, xpd);
if(CALL_XMETHOD(card_init, xbus, xpd) < 0)
goto err;
- list_add(&xpd->xpd_list, &xpd_list);
- xbus->xpds[xpd->id] = xpd;
- xbus->num_xpds++;
// Turn off all channels
CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ~0, 0);
xpd->card_present = 1;
- // Turn on enabled channels
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
+ // Turn on all channels
+ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ALL_LINES, 1);
if(zap_autoreg)
- xpd_zaptel_register(xpd);
+ zaptel_register_xpd(xpd);
out:
memset(card_desc, 0, sizeof(struct card_desc_struct));
kfree(card_desc);
@@ -372,10 +398,6 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
xpd->timer_count, xpd->span.mainttimer
);
len += sprintf(page + len, "STATES:");
- len += sprintf(page + len, "\n\t%-17s: ", "enabled");
- for_each_line(xpd, i) {
- len += sprintf(page + len, "%d ", IS_SET(xpd->enabled_chans, i));
- }
len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->digital_outputs, i));
@@ -469,8 +491,7 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
size_t alloc_size = sizeof(xpd_t) + privsize;
int i;
- INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
- xpd_num, revision / 10, revision % 10, xbus->busname);
+ DBG("%s: xpd #%d\n", xbus->busname, xpd_num);
if(!VALID_XPD_NUM(xpd_num)) {
ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num);
goto err;
@@ -498,7 +519,6 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
xpd->type = proto_table->type;
xpd->xproto = proto_table;
xpd->xops = &proto_table->xops;
- xpd->enabled_chans = enabled_channels[xpd_num];
xpd->digital_outputs = 0;
xpd->digital_inputs = 0;
@@ -535,6 +555,13 @@ err:
return NULL;
}
+/* FIXME: this should be removed once digium patch their zaptel.h
+ * I simply wish to avoid changing zaptel.h in the xpp patches.
+ */
+#ifndef ZT_EVENT_REMOVED
+#define ZT_EVENT_REMOVED (20)
+#endif
+
void xpd_disconnect(xpd_t *xpd)
{
unsigned long flags;
@@ -550,8 +577,15 @@ void xpd_disconnect(xpd_t *xpd)
if(!xpd->card_present) /* Multiple reports */
goto out;
xpd->card_present = 0;
- if(SPAN_REGISTERED(xpd))
+ if(SPAN_REGISTERED(xpd)) {
+ int i;
+
update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
+ /* TODO: Should this be done before releasing the spinlock? */
+ DBG("Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n");
+ for (i=0; i<xpd->span.channels; i++)
+ zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED);
+ }
out:
spin_unlock_irqrestore(&xpd->lock, flags);
}
@@ -562,12 +596,9 @@ void xpd_remove(xpd_t *xpd)
BUG_ON(!xpd);
xbus = xpd->xbus;
- INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
+ INFO("%s: Remove XPD #%d from\n", xbus->busname, xpd->id);
- xpd_zaptel_unregister(xpd);
- xbus->xpds[xpd->id] = NULL;
- list_del(&xpd->xpd_list);
- xbus->num_xpds--;
+ zaptel_unregister_xpd(xpd);
CALL_XMETHOD(card_remove, xbus, xpd);
xpd_free(xpd);
}
@@ -595,6 +626,18 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
DBG("Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
}
+void update_line_status(xpd_t *xpd, int pos, bool good)
+{
+ struct zt_chan *chan;
+
+ BUG_ON(!xpd);
+ chan = &xpd->chans[pos];
+ if(good)
+ zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
+ else
+ zt_hooksig(chan, ZT_RXSIG_ONHOOK);
+}
+
static void xpp_ring_generate(xpd_t *xpd)
{
int i;
@@ -616,7 +659,7 @@ static void xpp_ring_generate(xpd_t *xpd)
* Ring detect logic:
* fxo_power is toggled
*/
- for_each_enabled_line(xpd, i) {
+ for_each_line(xpd, i) {
if(xpd->ringing[i] || xpd->ringer_on[i]) {
// ring state is only changed once per second:
if((xpd->timer_count % 1000) == 0) {
@@ -764,9 +807,9 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe
DBG("%s: %s/%s %s\n", __FUNCTION__,
xpd->xbus->busname, xpd->xpdname, (zt_reg) ? "register" : "unregister");
if(zt_reg)
- ret = xpd_zaptel_register(xpd);
+ ret = zaptel_register_xpd(xpd);
else
- ret = xpd_zaptel_unregister(xpd);
+ ret = zaptel_unregister_xpd(xpd);
return (ret < 0) ? ret : count;
}
@@ -870,14 +913,14 @@ static void xpp_transmitprep(xpd_t *xpd)
wake_up_interruptible(&xpd->txstateq[i]);
}
}
- if(IS_SET(xpd->hookstate, i)) {
+ if(IS_SET(xpd->hookstate, i) || IS_SET(xpd->cid_on, i)) {
memcpy((u_char *)w, chans[i].writechunk, ZT_CHUNKSIZE);
// fill_beep((u_char *)w, 5);
}
w += ZT_CHUNKSIZE;
}
// if(xpd->hookstate != 0 || sync_master != xpd) {
- ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk);
+ ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate | xpd->cid_on, writechunk);
if(ret < 0) {
DBG("failed to write PCM %d\n", ret);
}
@@ -918,7 +961,7 @@ static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, co
spin_lock_irqsave(&chan->lock, flags);
for (x=0;x<ZT_CHUNKSIZE;x++) {
rxlin = ZT_XLAW(rxchunk[x], chan);
- rxlin = echo_can_update(chan->ec, ZT_XLAW(txchunk[x], chan), rxlin);
+ rxlin = xpp_echo_can_update(chan->ec, ZT_XLAW(txchunk[x], chan), rxlin);
rxchunk[x] = ZT_LIN2X((int)rxlin, chan);
}
spin_unlock_irqrestore(&chan->lock, flags);
@@ -950,6 +993,8 @@ static void xpp_receiveprep(xpd_t *xpd)
// memset((u_char *)readchunk, 0x5A, ZT_CHUNKSIZE); // DEBUG
// fill_beep((u_char *)readchunk, 1); // DEBUG: BEEP
memcpy(chans[i].readchunk, (u_char *)readchunk, ZT_CHUNKSIZE);
+ } else {
+ memset(chans[i].readchunk, 0x7F, ZT_CHUNKSIZE); // SILENCE
}
readchunk += ZT_CHUNKSIZE;
}
@@ -1051,7 +1096,7 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
xpd->idletxhookstate[pos] = FXS_LINE_CID; /* OHT mode when idle */
if (xpd->lasttxhook[pos] == FXS_LINE_ENABLED) {
/* Apply the change if appropriate */
- CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, BIT(pos)); // CALLER ID
+ CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos); // CALLER ID
}
DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos);
return -ENOTTY;
@@ -1062,6 +1107,13 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE));
return -ENOTTY;
default:
+ /* Some span-specific commands before we give up: */
+ if (xpd->xops->card_ioctl != NULL) {
+ x = xpd->xops->card_ioctl(xpd, pos, cmd, arg);
+ if (x != -ENOTTY)
+ return x;
+ }
+
DBG("ENOTTY: chan=%d cmd=0x%x\n", pos, cmd);
DBG(" IOC_TYPE=0x%02X\n", _IOC_TYPE(cmd));
DBG(" IOC_DIR=0x%02X\n", _IOC_DIR(cmd));
@@ -1078,85 +1130,12 @@ static int xpp_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
xpd_t *xpd = chan->pvt;
xbus_t *xbus;
int pos = chan->chanpos - 1;
- int ret = 0;
BUG_ON(!xpd);
xbus = xpd->xbus;
BUG_ON(!xbus);
-
DBG("Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig);
- if(xpd->direction == TO_PSTN) {
- /* XXX Enable hooksig for FXO XXX */
- switch(txsig) {
- case ZT_TXSIG_START:
- // DBG("%s: ZT_TXSIG_START (drop through.)\n", chan->name);
- case ZT_TXSIG_OFFHOOK:
- // DBG("%s: ZT_TXSIG_OFFHOOK\n", chan->name);
- do_sethook(xpd, pos, 1);
- break;
- case ZT_TXSIG_ONHOOK:
- // DBG("%s: ZT_TXSIG_ONHOOK\n", chan->name);
- do_sethook(xpd, pos, 0);
- break;
- default:
- NOTICE("Can't set tx state to %s (%d)\n", txsig2str(txsig), txsig);
- return -EINVAL;
- }
- } else { /* TO_PHONE */
- switch(txsig) {
- case ZT_TXSIG_ONHOOK:
- // DBG("%s: ZT_TXSIG_ONHOOK\n", chan->name);
- xpd->ringing[pos] = 0;
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
- switch(chan->sig) {
- case ZT_SIG_EM:
- case ZT_SIG_FXOKS:
- case ZT_SIG_FXOLS:
- xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
- break;
- case ZT_SIG_FXOGS:
- xpd->lasttxhook[pos] = FXS_LINE_TIPOPEN;
- break;
- }
- break;
- case ZT_TXSIG_OFFHOOK:
- // DBG("%s: ZT_TXSIG_OFFHOOK\n", chan->name);
- xpd->ringing[pos] = 0;
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
- switch(chan->sig) {
- case ZT_SIG_EM:
- xpd->lasttxhook[pos] = FXS_LINE_REV_ACTIVE;
- break;
- default:
- xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
- break;
- }
- break;
- case ZT_TXSIG_START:
- // DBG("%s: ZT_TXSIG_START\n", chan->name);
- xpd->lasttxhook[pos] = FXS_LINE_RING;
- xpd->ringing[pos] = 1;
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_RING %s digital output ON\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
- return ret;
- }
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
- break;
- case ZT_TXSIG_KEWL:
- // DBG("%s: ZT_TXSIG_KEWL\n", chan->name);
- xpd->lasttxhook[pos] = FXS_LINE_DISABLED;
- break;
- default:
- NOTICE("%s: Can't set tx state to %s (%d)\n", __FUNCTION__, txsig2str(txsig), txsig);
- return -EINVAL;
- }
- }
- return 0;
+ return CALL_XMETHOD(card_hooksig, xbus, xpd, pos, txsig);
}
#else
@@ -1254,6 +1233,29 @@ int (*hooksig)(struct zt_chan *chan, zt_txsig_t hookstate);
int (*sethook)(struct zt_chan *chan, int hookstate);
#endif
+#ifdef XPP_EC_CHUNK
+static int xpp_echocan(struct zt_chan *chan, int len)
+{
+ if(len == 0) { /* shut down */
+ /* zaptel calls this also during channel initialization */
+ if(chan->ec) {
+ xpp_echo_can_free(chan->ec);
+ }
+ return 0;
+ }
+ if(chan->ec) {
+ ERR("%s: Trying to override an existing EC (%p)\n", __FUNCTION__, chan->ec);
+ return -EINVAL;
+ }
+ chan->ec = xpp_echo_can_create(len, 0);
+ if(!chan->ec) {
+ ERR("%s: Failed creating xpp EC (len=%d)\n", __FUNCTION__, len);
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
#ifdef CONFIG_ZAPTEL_WATCHDOG
/*
* If the watchdog detects no received data, it will call the
@@ -1280,7 +1282,7 @@ static int xpp_watchdog(struct zt_span *span, int cause)
* - User action through /proc
* - During xpd_remove()
*/
-static int xpd_zaptel_unregister(xpd_t *xpd)
+static int zaptel_unregister_xpd(xpd_t *xpd)
{
unsigned long flags;
@@ -1303,18 +1305,17 @@ static int xpd_zaptel_unregister(xpd_t *xpd)
mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish.
spin_unlock_irqrestore(&xpd->lock, flags);
if(xpd->card_present)
- xpd->xops->card_zaptel_registration(xpd, 0);
+ xpd->xops->card_zaptel_preregistration(xpd, 0);
zt_unregister(&xpd->span);
+ if(xpd->card_present)
+ xpd->xops->card_zaptel_postregistration(xpd, 0);
return 0;
}
-static int xpd_zaptel_register(xpd_t *xpd)
+static int zaptel_register_xpd(xpd_t *xpd)
{
- struct zt_chan *cur_chan;
struct zt_span *span;
xbus_t *xbus;
- int sigfxs;
- int i;
int cn;
const xops_t *xops;
@@ -1325,7 +1326,6 @@ static int xpd_zaptel_register(xpd_t *xpd)
ERR("xpd %s already registered\n", xpd->xpdname);
return -EEXIST;
}
- sigfxs = ! (xpd->direction == TO_PHONE); /* signaling is opposite */
cn = xpd->channels;
DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
@@ -1334,46 +1334,7 @@ static int xpd_zaptel_register(xpd_t *xpd)
span = &xpd->span;
xbus = xpd->xbus;
- snprintf(span->name, MAX_SPANNAME, "%s/%s",
- xbus->busname, xpd->xpdname);
- snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s",
- xbus->num, xpd->id,
- (xpd->direction == TO_PHONE) ? "FXS" : "FXO"
- );
- for(i = 0; i < cn; i++) {
-
- cur_chan = &xpd->chans[i];
- DBG("setting channel %d (sigfxs=%d)\n", i, sigfxs);
- if(IS_SET(xpd->digital_outputs, i)) {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d/%d/%d", xbus->num, xpd->id, i);
- } else if(IS_SET(xpd->digital_inputs, i)) {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d/%d/%d", xbus->num, xpd->id, i);
- } else {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d/%d/%d", (sigfxs) ? "FXO" : "FXS", xbus->num, xpd->id, i);
- }
- cur_chan->chanpos = i + 1;
- cur_chan->pvt = xpd;
- if (sigfxs)
- cur_chan->sigcap =
-#if 1
- ZT_SIG_FXSKS |
- ZT_SIG_FXSLS |
-#else
- ZT_SIG_SF |
-#endif
- 0;
- else
- cur_chan->sigcap =
-#if 1
- ZT_SIG_FXOKS |
- ZT_SIG_FXOLS |
- ZT_SIG_FXOGS |
-#else
- ZT_SIG_SF |
- ZT_SIG_EM |
-#endif
- 0;
- }
+ snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname);
span->deflaw = ZT_LAW_MULAW;
init_waitqueue_head(&span->maintq);
span->pvt = xpd;
@@ -1394,22 +1355,21 @@ static int xpd_zaptel_register(xpd_t *xpd)
#endif
span->ioctl = xpp_ioctl;
span->maint = xpp_maint;
+#ifdef XPP_EC_CHUNK
+ span->echocan = xpp_echocan;
+#endif
#ifdef CONFIG_ZAPTEL_WATCHDOG
span->watchdog = xpp_watchdog;
#endif
- DBG("Finished span_load: ZT_FLAG_RUNNING=%d\n", span->flags & ZT_FLAG_RUNNING);
-
DBG("Registering span of %s.\n", xpd->xpdname);
+ xpd->xops->card_zaptel_preregistration(xpd, 1);
if(zt_register(&xpd->span, 1)) {
xbus_t *xbus = xpd->xbus;
- ERR("Failed to zt_register of span of xpd %s.\n", xpd->xpdname);
- xbus->xpds[xpd->id] = NULL;
- list_del(&xpd->xpd_list);
- xbus->num_xpds--;
+ ERR("%s/%s: Failed to zt_register span\n", xbus->busname, xpd->xpdname);
return -ENODEV;
}
- xpd->xops->card_zaptel_registration(xpd, 1);
+ xpd->xops->card_zaptel_postregistration(xpd, 1);
return 0;
}
@@ -1498,7 +1458,7 @@ static ssize_t xpp_sys_write (struct file * file, const char __user * buf,
if (copy_from_user (pack_tx->content.raw, buf, count)) {
return -EFAULT;
}
- XPD_ADDR_SET(pack_tx->content.addr, xpdnum);
+ xpd_set_addr(&pack_tx->content.addr, xpdnum);
pack_tx->datalen = count;
// pack_tx->flags |= XPP_PACKET_FIREANDFORGET;
DBG("sending op=%d to %d\n", pack_tx->content.opcode, xpdnum);
@@ -1528,11 +1488,6 @@ static void do_cleanup(void)
{
if(timer_pending(&xpp_timer))
del_timer_sync(&xpp_timer);
- if (xpp_worker) {
- flush_workqueue(xpp_worker);
- destroy_workqueue(xpp_worker);
- xpp_worker = NULL;
- }
#if 0
unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
#endif
@@ -1582,12 +1537,6 @@ int __init xpp_zap_init(void)
ent->write_proc = proc_sync_write;
ent->data = NULL;
#endif
- xpp_worker = create_singlethread_workqueue("xppworker");
- if(!xpp_worker) {
- ERR("Failed to create card detector workqueue.\n");
- do_cleanup();
- return -ENOMEM;
- }
ret = xbus_core_init();
if(ret) {
ERR("xbus_core_init failed (%d)\n", ret);
@@ -1621,6 +1570,7 @@ EXPORT_SYMBOL(xpd_alloc);
EXPORT_SYMBOL(xpd_disconnect);
EXPORT_SYMBOL(packet_send);
EXPORT_SYMBOL(update_xpd_status);
+EXPORT_SYMBOL(update_line_status);
EXPORT_SYMBOL(fill_beep);
EXPORT_SYMBOL(xpp_tick);
EXPORT_SYMBOL(xpp_open);