diff options
Diffstat (limited to 'xpp/cards.c')
-rw-r--r-- | xpp/cards.c | 394 |
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]; +} |