summaryrefslogtreecommitdiff
path: root/xpp/cards.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/cards.c')
-rw-r--r--xpp/cards.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/xpp/cards.c b/xpp/cards.c
new file mode 100644
index 0000000..dec0570
--- /dev/null
+++ b/xpp/cards.c
@@ -0,0 +1,394 @@
+#include <linux/module.h>
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xpp_proto.h"
+#include "cards.h"
+
+static char rcsid[] = "$Id$";
+
+extern int print_dbg;
+#include "zap_debug.h"
+
+#define MAX_SLIC_REGISTERS 100
+
+struct FXS_private_data {
+ slic_reply_t last_slic_reply;
+};
+
+/*------------------------- FXS Functions --------------------------*/
+int FXS_card_new(xpd_t *xpd)
+{
+ xpd->direction = TO_PHONE;
+ xpd->channels = min(8, CHANNELS_PERXPD);
+ if(xpd->id == 0) {
+ DBG("First XPD detected. Initialize digital outputs\n");
+ xpd->channels += 2;
+ xpd->digital_outputs = BIT(8) | BIT(9); // Two extra channels
+ }
+ return 0;
+}
+
+int FXS_card_remove(xpd_t *xpd)
+{
+ return 0;
+}
+
+static int FXS_card_startup(struct zt_span *span)
+{
+ DBG("\n");
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int FXS_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ xpd_t *xpd = span->pvt;
+
+ DBG("%s\n", xpd->xpdname);
+ return 0;
+}
+
+/* Set signalling type (if appropriate) */
+static int FXS_card_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
+ dump_sigtype(print_dbg, " ", sigtype);
+ // FIXME: sanity checks:
+ // - should be supported (within the sigcap)
+ // - should not replace fxs <->fxo ??? (covered by previous?)
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int FXS_card_shutdown(struct zt_span *span)
+{
+ xpd_t *xpd = span->pvt;
+
+ DBG("%s\n", xpd->xpdname);
+ return 0;
+}
+
+static int FXS_card_sethook(struct zt_chan *chan, int hookstate)
+{
+ int pos = chan->chanpos - 1;
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus;
+ int ret = 0;
+
+ if(!xpd) {
+ ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
+ return -EINVAL;
+ }
+ xbus = xpd->xbus;
+ // DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
+ switch(hookstate) {
+ /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
+ * Can be ignored for an FXS line
+ */
+ case ZT_ONHOOK:
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
+ ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
+ return ret;
+ }
+ DBG("ZT_ONHOOK: %s hookstate=0x%04X (stop ringing pos=%d)\n", chan->name, xpd->hookstate, pos);
+ xpd->ringing[pos] = 0;
+#if 1 // FIXME: Not needed -- verify
+ ret = CALL_PROTO(RING, xbus, xpd, pos, 0); // RING off
+#endif
+ ret = CALL_PROTO(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
+ ret = CALL_PROTO(CHAN_POWER, xbus, xpd, BIT(pos), 0); // Power down (prevent overheating!!!)
+ if(ret) {
+ DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
+ break;
+ }
+ break;
+ case ZT_START:
+ DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
+ // Fall through
+ case ZT_OFFHOOK:
+ DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (FXS)\n", chan->name, xpd->hookstate);
+ break;
+ case ZT_WINK:
+ DBG("ZT_WINK %s\n", chan->name);
+ break;
+ case ZT_FLASH:
+ DBG("ZT_FLASH %s\n", chan->name);
+ break;
+ case ZT_RING:
+ DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("ZT_ONHOOK %s digital output ON\n", chan->name);
+ ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
+ return ret;
+ }
+ xpd->ringing[pos] = RINGS_NUM*2;
+ ret = CALL_PROTO(CHAN_POWER, xbus, xpd, (1 << pos), 1); // Power up (for ring)
+ ret = CALL_PROTO(RING, xbus, xpd, pos, 1); // RING on
+ if(ret) {
+ DBG("ZT_RING Failed: ret=0x%02X\n", ret);
+ }
+ break;
+ case ZT_RINGOFF:
+ DBG("ZT_RINGOFF %s\n", chan->name);
+ break;
+ default:
+ DBG("UNKNOWN hookstate=0x%X\n", hookstate);
+ }
+ return ret;
+}
+
+static int FXS_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ default:
+ return xpp_ioctl(chan, cmd, arg);
+ }
+ return 0;
+}
+
+#if 0
+int FXS_zaptel_setup(xpd_t *xpd)
+{
+ struct zt_chan *cur_chan;
+ struct zt_span *span;
+ xbus_t *xbus;
+ int i;
+ int cn;
+
+ BUG_ON(!xpd);
+
+ sigfxs = ! (xpd->direction == TO_PHONE); /* signaling is opposite */
+ cn = xpd->channels;
+ DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
+
+ xpd->chans = kmalloc(sizeof(struct zt_chan)*cn, GFP_ATOMIC);
+ if (xpd->chans == NULL) {
+ ERR("xpd: Unable to allocate channels\n");
+ return -ENOMEM;
+ }
+ memset(xpd->chans, 0, sizeof(struct zt_chan)*cn);
+ memset(&xpd->span, 0, sizeof(struct zt_span));
+
+ span = &xpd->span;
+ xbus = xpd->xbus;
+ snprintf(span->name, MAX_SPANNAME, "%s/%s",
+ xbus->busname, xpd->xpdname);
+ {
+ char tmp[MAX_SPANNAME];
+ struct xpd_sim *sim = &xbus->sim[xpd->id];
+
+ if(sim->simulated)
+ snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
+ else
+ tmp[0] = '\0';
+
+ snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
+ xbus->num, xpd->id,
+ (xpd->direction == TO_PHONE) ? "FXS" : "FXO",
+ tmp
+ );
+ }
+ for(i = 0; i < cn; i++) {
+
+ cur_chan = &xpd->chans[i];
+ DBG("setting channel %d\n", i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%d-%d", xpd->id, i);
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ cur_chan->sigcap =
+#if 1
+ ZT_SIG_FXOKS |
+ ZT_SIG_FXOLS |
+ ZT_SIG_FXOGS |
+#else
+ ZT_SIG_SF |
+ ZT_SIG_EM |
+#endif
+ 0;
+ }
+ span->deflaw = ZT_LAW_MULAW;
+ init_waitqueue_head(&span->maintq);
+ span->pvt = xpd;
+ span->channels = cn;
+ span->chans = xpd->chans;
+
+ span->startup = FXS_xpp_startup;
+ span->shutdown = FXS_xpp_shutdown;
+ span->spanconfig = FXS_xpp_spanconfig;
+ span->chanconfig = FXS_xpp_chanconfig;
+ span->open = xpp_open;
+ span->close = xpp_close;
+#ifdef WITH_RBS
+ span->flags = ZT_FLAG_RBS;
+ span->hooksig = xpp_hooksig; /* Only with RBS bits */
+#else
+ span->sethook = FXS_xpp_sethook;
+#endif
+ span->ioctl = FXS_xpp_ioctl;
+ span->maint = xpp_maint;
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ span->watchdog = xpp_watchdog;
+#endif
+
+ return 0;
+}
+#endif
+
+int FXS_zaptel_cleanup(xpd_t *xpd)
+{
+ return 0;
+}
+
+/*------------------------- FXO Functions --------------------------*/
+static int FXO_card_new(xpd_t *xpd)
+{
+ xpd->direction = TO_TRUNK;
+ xpd->channels = min(8, CHANNELS_PERXPD);
+ return 0;
+}
+
+static int FXO_card_remove(xpd_t *xpd)
+{
+ return 0;
+}
+
+static int FXO_card_startup(struct zt_span *span)
+{
+ DBG("\n");
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int FXO_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ xpd_t *xpd = span->pvt;
+
+ DBG("%s\n", xpd->xpdname);
+ return 0;
+}
+
+/* Set signalling type (if appropriate) */
+static int FXO_card_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
+ dump_sigtype(print_dbg, " ", sigtype);
+ // FIXME: sanity checks:
+ // - should be supported (within the sigcap)
+ // - should not replace fxs <->fxo ??? (covered by previous?)
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int FXO_card_shutdown(struct zt_span *span)
+{
+ xpd_t *xpd = span->pvt;
+
+ DBG("%s\n", xpd->xpdname);
+ return 0;
+}
+
+
+static int FXO_card_sethook(struct zt_chan *chan, int hookstate)
+{
+ int pos = chan->chanpos - 1;
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus;
+ int ret = 0;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ // DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
+ switch(hookstate) {
+ /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
+ * Can be ignored for an FXS line
+ */
+ case ZT_ONHOOK:
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
+ ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
+ return ret;
+ }
+ DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
+ xpd->ringing[pos] = 0;
+ BIT_CLR(xpd->hookstate, pos);
+ ret = CALL_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
+ if(ret) {
+ DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
+ break;
+ }
+ break;
+ case ZT_START:
+ DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
+ // Fall through
+ case ZT_OFFHOOK:
+ DBG("ZT_OFFHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
+ BIT_SET(xpd->hookstate, pos);
+ xpd->ringing[pos] = 0;
+ ret = CALL_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
+ if(ret) {
+ DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
+ break;
+ }
+ break;
+ case ZT_WINK:
+ DBG("ZT_WINK %s\n", chan->name);
+ break;
+ case ZT_FLASH:
+ DBG("ZT_FLASH %s\n", chan->name);
+ break;
+ case ZT_RING:
+ DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
+ break;
+ case ZT_RINGOFF:
+ DBG("ZT_RINGOFF %s\n", chan->name);
+ break;
+ default:
+ DBG("UNKNOWN hookstate=0x%X\n", hookstate);
+ }
+ return ret;
+}
+
+static int FXO_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ default:
+ return xpp_ioctl(chan, cmd, arg);
+ }
+ return 0;
+}
+
+
+/*------------------------- Function table -------------------------*/
+
+#define DEF_(t) \
+ [XPD_TYPE_ ## t] { \
+ .card_new = t ## _card_new, \
+ .card_remove = t ## _card_remove, \
+ .card_startup = t ## _card_startup, \
+ .card_shutdown = t ## _card_shutdown, \
+ .card_spanconfig = t ## _card_spanconfig, \
+ .card_chanconfig = t ## _card_chanconfig, \
+ .card_sethook = t ## _card_sethook, \
+ .card_ioctl = t ## _card_ioctl, \
+ }
+
+xops_t xpd_card_ops[XPD_TYPE_NOMODULE] = {
+ DEF_(FXS),
+ DEF_(FXO)
+};
+
+xops_t *get_xops(xpd_type_t xpd_type)
+{
+ if(xpd_type >= XPD_TYPE_NOMODULE)
+ return NULL;
+ return &xpd_card_ops[xpd_type];
+}