This branch splits all the analog signaling logic out of chan_dahdi.c into
sig_analog.c. Functionality in theory should not change at all. As noted
in the code, there is still some unused code remaining that will be cleaned
up in a later commit.
static int dahdi_sendtext(struct ast_channel *c, const char *text);
+static int analog_lib_handles(int signalling, int radio, int oprmode);
+
static void mwi_event_cb(const struct ast_event *event, void *userdata)
{
/* This module does not handle MWI in an event-based manner. However, it
@@ -753,6 +756,7 @@
static struct dahdi_pvt {
ast_mutex_t lock;
+ struct callerid_state *cs;
struct ast_channel *owner; /*!< Our current active owner (if applicable) */
/*!< Up to three channels can be associated with this call */
@@ -1333,6 +1337,7 @@
char begindigit;
/*! \brief TRUE if confrence is muted. */
int muting;
+ void *sig_pvt;
} *iflist = NULL, *ifend = NULL;
/*! \brief Channel configuration from chan_dahdi.conf .
@@ -1527,6 +1532,911 @@
#else
#define GET_CHANNEL(p) ((p)->channel)
#endif
+
+static enum analog_sigtype dahdisig_to_analogsig(int sig)
+{
+ switch (sig) {
+ case SIG_FXOLS:
+ return ANALOG_SIG_FXOLS;
+ case SIG_FXOGS:
+ return ANALOG_SIG_FXOGS;
+ case SIG_FXOKS:
+ return ANALOG_SIG_FXOKS;
+ case SIG_FXSLS:
+ return ANALOG_SIG_FXSLS;
+ case SIG_FXSGS:
+ return ANALOG_SIG_FXSGS;
+ case SIG_FXSKS:
+ return ANALOG_SIG_FXSKS;
+ case SIG_EMWINK:
+ return ANALOG_SIG_EMWINK;
+ case SIG_EM:
+ return ANALOG_SIG_EM;
+ case SIG_EM_E1:
+ return ANALOG_SIG_EM_E1;
+ case SIG_FEATD:
+ return ANALOG_SIG_FEATD;
+ case SIG_FEATDMF:
+ return ANALOG_SIG_FEATDMF;
+ case SIG_E911:
+ return SIG_E911;
+ case SIG_FGC_CAMA:
+ return ANALOG_SIG_FGC_CAMA;
+ case SIG_FGC_CAMAMF:
+ return ANALOG_SIG_FGC_CAMAMF;
+ case SIG_FEATB:
+ return ANALOG_SIG_FEATB;
+ case SIG_SFWINK:
+ return ANALOG_SIG_SFWINK;
+ case SIG_SF:
+ return ANALOG_SIG_SF;
+ case SIG_SF_FEATD:
+ return ANALOG_SIG_SF_FEATD;
+ case SIG_SF_FEATDMF:
+ return ANALOG_SIG_SF_FEATDMF;
+ case SIG_FEATDMF_TA:
+ return ANALOG_SIG_FEATDMF_TA;
+ case SIG_SF_FEATB:
+ return ANALOG_SIG_FEATB;
+ default:
+ return -1;
+ }
+}
+
+
+static int analog_tone_to_dahditone(enum analog_tone tone)
+{
+ switch (tone) {
+ case ANALOG_TONE_RINGTONE:
+ return DAHDI_TONE_RINGTONE;
+ case ANALOG_TONE_STUTTER:
+ return DAHDI_TONE_STUTTER;
+ case ANALOG_TONE_CONGESTION:
+ return DAHDI_TONE_CONGESTION;
+ case ANALOG_TONE_DIALTONE:
+ return DAHDI_TONE_DIALTONE;
+ case ANALOG_TONE_DIALRECALL:
+ return DAHDI_TONE_DIALRECALL;
+ case ANALOG_TONE_INFO:
+ return DAHDI_TONE_INFO;
+ default:
+ return -1;
+ }
+}
+
+static int analogsub_to_dahdisub(enum analog_sub analogsub)
+{
+ int index;
+
+ switch (analogsub) {
+ case ANALOG_SUB_REAL:
+ index = SUB_REAL;
+ break;
+ case ANALOG_SUB_CALLWAIT:
+ index = SUB_CALLWAIT;
+ break;
+ case ANALOG_SUB_THREEWAY:
+ index = SUB_THREEWAY;
+ break;
+ default:
+ ast_log(LOG_ERROR, "Unidentified sub!\n");
+ index = SUB_REAL;
+ }
+
+ return index;
+}
+
+static enum analog_event dahdievent_to_analogevent(int event);
+static int bump_gains(struct dahdi_pvt *p);
+static int dahdi_setlinear(int dfd, int linear);
+
+static int my_start_cid_detect(void *pvt, int cid_signalling)
+{
+ struct dahdi_pvt *p = pvt;
+ int index = SUB_REAL;
+ p->cs = callerid_new(cid_signalling);
+ if (!p->cs) {
+ ast_log(LOG_ERROR, "Unable to alloc callerid\n");
+ return -1;
+ }
+ bump_gains(p);
+ dahdi_setlinear(p->subs[index].dfd, 0);
+
+ return 0;
+}
+
+static int my_stop_cid_detect(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int index = SUB_REAL;
+ if (p->cs)
+ callerid_free(p->cs);
+ dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
+ return 0;
+}
+
+static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
+{
+ struct dahdi_pvt *p = pvt;
+ struct pollfd poller;
+ char *name, *num;
+ int index = SUB_REAL;
+ int res;
+ unsigned char buf[256];
+ int flags;
+
+ poller.fd = p->subs[SUB_REAL].dfd;
+ poller.events = POLLPRI | POLLIN;
+ poller.revents = 0;
+
+ res = poll(&poller, 1, timeout);
+
+ if (poller.revents & POLLPRI) {
+ *ev = dahdievent_to_analogevent(dahdi_get_event(p->subs[SUB_REAL].dfd));
+ return 1;
+ }
+
+ if (poller.revents & POLLIN) {
+ /*** NOTES ***/
+ /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
+ * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
+ * either a timeout occurss or CID is detected (returns 0). returning 1 should be event received, and -1 should be fail
+ * and die */
+ res = read(p->subs[index].dfd, buf, sizeof(buf));
+ if (res < 0) {
+ if (errno != ELAST) {
+ ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
+ callerid_free(p->cs);
+ return -1;
+ }
+ }
+ res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+ if (res < 0) {
+ ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (res == 1) {
+ callerid_get(p->cs, &name, &num, &flags);
+ if (name)
+ ast_copy_string(namebuf, name, ANALOG_MAX_CID);
+ if (num)
+ ast_copy_string(numbuf, num, ANALOG_MAX_CID);
+
+ ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
+ return 0;
+ }
+ }
+
+ *ev = ANALOG_EVENT_NONE;
+ return 1;
+}
+
+static int send_callerid(struct dahdi_pvt *p);
+
+static int my_stop_callwait(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ p->callwaitingrepeat = 0;
+ p->cidcwexpire = 0;
+
+ return 0;
+}
+
+static int save_conference(struct dahdi_pvt *p);
+
+static int my_callwait(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
+ if (p->cidspill) {
+ ast_log(LOG_WARNING, "Spill already exists?!?\n");
+ free(p->cidspill);
+ }
+ if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
+ return -1;
+ save_conference(p);
+ /* Silence */
+ memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
+ if (!p->callwaitrings && p->callwaitingcallerid) {
+ ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
+ p->callwaitcas = 1;
+ p->cidlen = 2400 + 680 + READ_SIZE * 4;
+ } else {
+ ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
+ p->callwaitcas = 0;
+ p->cidlen = 2400 + READ_SIZE * 4;
+ }
+ p->cidpos = 0;
+ send_callerid(p);
+
+ return 0;
+}
+
+static int my_send_callerid(void *pvt, int cwcid, struct ast_callerid *cid)
+{
+ struct dahdi_pvt *p = pvt;
+
+ ast_log(LOG_ERROR, "Starting cid spill\n");
+
+ if (p->cidspill) {
+ ast_log(LOG_WARNING, "cidspill already exists??\n");
+ free(p->cidspill);
+ }
+
+ if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
+ if (cwcid == 0) {
+ p->cidlen = ast_callerid_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
+ } else {
+ p->callwaitcas = 0;
+ p->cidcwexpire = 0;
+ p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
+ p->cidlen += READ_SIZE * 4;
+ }
+ p->cidpos = 0;
+ send_callerid(p);
+ }
+ return 0;
+}
+
+static int my_dsp_reset_and_flush_digits(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ if (p->dsp)
+ ast_dsp_digitreset(p->dsp);
+
+ return 0;
+}
+
+static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
+{
+ struct dahdi_pvt *p = pvt;
+
+ if (p->channel == CHAN_PSEUDO)
+ ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
+
+ if (mode == ANALOG_DIGITMODE_DTMF) {
+ /* If we do hardware dtmf, no need for a DSP */
+ if (p->hardwaredtmf) {
+ if (p->dsp) {
+ ast_dsp_free(p->dsp);
+ p->dsp = NULL;
+ }
+ return 0;
+ }
+
+ if (!p->dsp) {
+ p->dsp = ast_dsp_new();
+ if (!p->dsp) {
+ ast_log(LOG_ERROR, "Unable to allocate DSP\n");
+ return -1;
+ }
+ }
+
+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
+ } else if (mode == ANALOG_DIGITMODE_MF) {
+ if (!p->dsp) {
+ p->dsp = ast_dsp_new();
+ if (!p->dsp) {
+ ast_log(LOG_ERROR, "Unable to allocate DSP\n");
+ return -1;
+ }
+ }
+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
+ }
+ return 0;
+}
+
+static int dahdi_wink(struct dahdi_pvt *p, int index);
+
+static int my_wink(void *pvt, enum analog_sub sub)
+{
+ struct dahdi_pvt *p = pvt;
+ int index = analogsub_to_dahdisub(sub);
+ if (index != SUB_REAL) {
+ ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
+ }
+ return dahdi_wink(p, index);
+}
+
+static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri);
+
+static int reset_conf(struct dahdi_pvt *p);
+
+static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
+
+static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+{
+ struct ast_frame *f = *dest;
+ struct dahdi_pvt *p = pvt;
+ int idx = analogsub_to_dahdisub(analog_index);
+
+ ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
+
+ if (f->subclass == 'f') {
+ /* Fax tone -- Handle and return NULL */
+ if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+ /* If faxbuffers are configured, use them for the fax transmission */
+ if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+ struct dahdi_bufferinfo bi = {
+ .txbufpolicy = p->faxbuf_policy,
+ .bufsize = p->bufsize,
+ .numbufs = p->faxbuf_no
+ };
+ int res;
+
+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+ ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+ } else {
+ p->bufferoverrideinuse = 1;
+ }
+ }
+ p->faxhandled = 1;
+ if (strcmp(ast->exten, "fax")) {
+ const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+ /* We need to unlock 'ast' here because ast_exists_extension has the
+ * potential to start autoservice on the channel. Such action is prone
+ * to deadlock.
+ */
+ ast_mutex_unlock(&p->lock);
+ ast_channel_unlock(ast);
+ if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+ /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+ if (ast_async_goto(ast, target_context, "fax", 1))
+ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+ } else {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+ }
+ } else {
+ ast_debug(1, "Already in a fax extension, not redirecting\n");
+ }
+ } else {
+ ast_debug(1, "Fax already handled\n");
+ }
+ dahdi_confmute(p, 0);
+ p->subs[idx].f.frametype = AST_FRAME_NULL;
+ p->subs[idx].f.subclass = 0;
+ *dest = &p->subs[idx].f;
+ }
+}
+
+static void my_lock_private(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ ast_mutex_lock(&p->lock);
+}
+
+static void my_unlock_private(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ ast_mutex_unlock(&p->lock);
+}
+
+static void my_increase_ss_count(void)
+{
+ ast_mutex_lock(&ss_thread_lock);
+ ss_thread_count++;
+ ast_mutex_unlock(&ss_thread_lock);
+}
+
+static void my_decrease_ss_count(void)
+{
+ ast_mutex_lock(&ss_thread_lock);
+ ss_thread_count--;
+ ast_cond_signal(&ss_thread_complete);
+ ast_mutex_unlock(&ss_thread_lock);
+}
+
+static void my_all_subchannels_hungup(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int res, law;
+
+ p->faxhandled = 0;
+ p->didtdd = 0;
+
+ if (p->dsp) {
+ ast_dsp_free(p->dsp);
+ p->dsp = NULL;
+ }
+
+ law = DAHDI_LAW_DEFAULT;
+ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
+ if (res < 0)
+ ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
+
+ dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
+
+#if 1
+ {
+ int i;
+ p->owner = NULL;
+ /* Cleanup owners here */
+ for (i = 0; i < 3; i++) {
+ p->subs[i].owner = NULL;
+ }
+ }
+#endif
+
+ reset_conf(p);
+ if (num_restart_pending == 0) {
+ restart_monitor();
+ }
+}
+
+static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
+
+static int my_conf_del(void *pvt, enum analog_sub sub)
+{
+ struct dahdi_pvt *p = pvt;
+ int x = analogsub_to_dahdisub(sub);
+
+ return conf_del(p, &p->subs[x], x);
+}
+
+static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
+
+static int my_conf_add(void *pvt, enum analog_sub sub)
+{
+ struct dahdi_pvt *p = pvt;
+ int x = analogsub_to_dahdisub(sub);
+
+ return conf_add(p, &p->subs[x], x, 0);
+}
+
+static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
+
+static int my_complete_conference_update(void *pvt, int needconference)
+{
+ struct dahdi_pvt *p = pvt;
+ int needconf = needconference;
+ int x;
+ int useslavenative;
+ struct dahdi_pvt *slave = NULL;
+
+ useslavenative = isslavenative(p, &slave);
+
+ /* If we have a slave, add him to our conference now. or DAX
+ if this is slave native */
+ for (x = 0; x < MAX_SLAVES; x++) {
+ if (p->slaves[x]) {
+ if (useslavenative)
+ conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
+ else {
+ conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
+ needconf++;
+ }
+ }
+ }
+ /* If we're supposed to be in there, do so now */
+ if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
+ if (useslavenative)
+ conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
+ else {
+ conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
+ needconf++;
+ }
+ }
+ /* If we have a master, add ourselves to his conference */
+ if (p->master) {
+ if (isslavenative(p->master, NULL)) {
+ conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
+ } else {
+ conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
+ }
+ }
+ if (!needconf) {
+ /* Nobody is left (or should be left) in our conference.
+ Kill it. */
+ p->confno = -1;
+ }
+
+ return 0;
+}
+
+static int check_for_conference(struct dahdi_pvt *p);
+
+static int my_check_for_conference(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ return check_for_conference(p);
+}
+
+static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
+{
+ struct dahdi_pvt *p = pvt;
+ int da, db;
+ int tchan;
+
+ da = analogsub_to_dahdisub(a);
+ db = analogsub_to_dahdisub(b);
+
+ tchan = p->subs[da].chan;
+
+ p->subs[da].chan = p->subs[db].chan;
+
+ p->subs[db].chan = tchan;
+
+ if (ast_a)
+ ast_a->fds[0] = p->subs[da].dfd;
+ if (ast_b)
+ ast_b->fds[0] = p->subs[db].dfd;
+
+ p->subs[da].owner = ast_a;
+ p->subs[db].owner = ast_b;
+
+ wakeup_sub(p, a, NULL);
+ wakeup_sub(p, b, NULL);
+
+ return;
+}
+
+static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
+
+static struct ast_channel * my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub)
+{
+ struct dahdi_pvt *p = pvt;
+ int dsub = analogsub_to_dahdisub(sub);
+
+ return dahdi_new(p, state, startpbx, dsub, 0, 0);
+}
+
+static int unalloc_sub(struct dahdi_pvt *p, int x);
+
+static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
+{
+ struct dahdi_pvt *p = pvt;
+
+ return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
+}
+
+static int alloc_sub(struct dahdi_pvt *p, int x);
+
+static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
+{
+ struct dahdi_pvt *p = pvt;
+
+ return alloc_sub(p, analogsub_to_dahdisub(analogsub));
+}
+
+static int has_voicemail(struct dahdi_pvt *p);
+
+static int my_has_voicemail(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ return has_voicemail(p);
+}
+
+static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
+{
+ struct dahdi_pvt *p = pvt;
+ int index;
+
+ index = analogsub_to_dahdisub(sub);
+
+ return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
+}
+
+static enum analog_event dahdievent_to_analogevent(int event)
+{
+ enum analog_event res = ANALOG_EVENT_ERROR;
+
+ switch (event) {
+ case DAHDI_EVENT_DIALCOMPLETE:
+ res = ANALOG_EVENT_DIALCOMPLETE;
+ break;
+ case DAHDI_EVENT_WINKFLASH:
+ res = ANALOG_EVENT_WINKFLASH;
+ break;
+ case DAHDI_EVENT_ONHOOK:
+ res = ANALOG_EVENT_ONHOOK;
+ break;
+ case DAHDI_EVENT_RINGOFFHOOK:
+ res = ANALOG_EVENT_RINGOFFHOOK;
+ break;
+ case DAHDI_EVENT_ALARM:
+ res = ANALOG_EVENT_ALARM;
+ break;
+ case DAHDI_EVENT_NOALARM:
+ res = ANALOG_EVENT_NOALARM;
+ break;
+ case DAHDI_EVENT_HOOKCOMPLETE:
+ res = ANALOG_EVENT_HOOKCOMPLETE;
+ break;
+ case DAHDI_EVENT_POLARITY:
+ res = ANALOG_EVENT_POLARITY;
+ break;
+ case DAHDI_EVENT_RINGERON:
+ res = ANALOG_EVENT_RINGERON;
+ break;
+ case DAHDI_EVENT_RINGEROFF:
+ res = ANALOG_EVENT_RINGEROFF;
+ break;
+ case DAHDI_EVENT_RINGBEGIN:
+ res = ANALOG_EVENT_RINGBEGIN;
+ break;
+ case DAHDI_EVENT_PULSE_START:
+ res = ANALOG_EVENT_PULSE_START;
+ break;
+ case DAHDI_EVENT_NEONMWI_ACTIVE:
+ res = ANALOG_EVENT_NEONMWI_ACTIVE;
+ break;
+ case DAHDI_EVENT_NEONMWI_INACTIVE:
+ res = ANALOG_EVENT_NEONMWI_INACTIVE;
+ break;
+ }
+
+ return res;
+}
+
+static inline int dahdi_wait_event(int fd);
+
+static int my_wait_event(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ return dahdi_wait_event(p->subs[SUB_REAL].dfd);
+}
+
+static int my_get_event(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int res;
+
+ if (p->fake_event) {
+ res = p->fake_event;
+ p->fake_event = 0;
+ } else
+ res = dahdi_get_event(p->subs[SUB_REAL].dfd);
+
+ return dahdievent_to_analogevent(res);
+}
+
+static int my_is_off_hook(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int res;
+ struct dahdi_params par;
+
+ if (p->subs[SUB_REAL].dfd > -1)
+ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
+ else {
+ /* Assume not off hook on CVRS */
+ res = 0;
+ par.rxisoffhook = 0;
+ }
+ if (res) {
+ ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
+ }
+
+ return (par.rxbits > -1) || par.rxisoffhook;
+}
+
+static void dahdi_enable_ec(struct dahdi_pvt *p);
+static void dahdi_disable_ec(struct dahdi_pvt *p);
+
+static int my_set_echocanceller(void *pvt, int enable)
+{
+ struct dahdi_pvt *p = pvt;
+
+ if (enable)
+ dahdi_enable_ec(p);
+ else
+ dahdi_disable_ec(p);
+
+ return 0;
+}
+
+static int dahdi_ring_phone(struct dahdi_pvt *p);
+
+static int my_ring(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ return dahdi_ring_phone(p);
+}
+
+static inline int dahdi_set_hook(int fd, int hs);
+
+static int my_off_hook(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
+}
+
+static int my_start(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int x = DAHDI_START;
+
+ return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
+}
+
+static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
+{
+ int index = analogsub_to_dahdisub(sub);
+ int res;
+ struct dahdi_pvt *p = pvt;
+ struct dahdi_dialoperation ddop;
+
+ if (dop->op != ANALOG_DIAL_OP_REPLACE) {
+ ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
+ return -1;
+ }
+
+ if (sub != ANALOG_SUB_REAL)
+ printf("Trying to dial digits on sub %d\n", sub);
+
+ ddop.op = DAHDI_DIAL_OP_REPLACE;
+ strncpy(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
+
+ printf("Dialing %s on %d\n", ddop.dialstr, p->channel);
+
+ res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
+
+ if (res == -1)
+ ast_log(LOG_DEBUG, "DAHDI_DIAL ioctl failed on %s: %s\n", p->owner->name, strerror(errno));
+
+ return res;
+}
+
+static void dahdi_train_ec(struct dahdi_pvt *p);
+
+static int my_train_echocanceller(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ dahdi_train_ec(p);
+
+ return 0;
+}
+
+static int my_is_dialing(void *pvt, enum analog_sub sub)
+{
+ struct dahdi_pvt *p = pvt;
+ int index;
+ int x;
+
+ index = analogsub_to_dahdisub(sub);
+
+ if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
+ ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed!\n");
+ return -1;
+ }
+
+ return x;
+}
+
+static int my_on_hook(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int x = DAHDI_ONHOOK;
+
+ return ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_HOOK, &x);
+}
+
+/*!
+ * \brief Send MWI state change
+ *
+ * \arg mailbox_full This is the mailbox associated with the FXO line that the
+ * MWI state has changed on.
+ * \arg thereornot This argument should simply be set to 1 or 0, to indicate
+ * whether there are messages waiting or not.
+ *
+ * \return nothing
+ *
+ * This function does two things:
+ *
+ * 1) It generates an internal Asterisk event notifying any other module that
+ * cares about MWI that the state of a mailbox has changed.
+ *
+ * 2) It runs the script specified by the mwimonitornotify option to allow
+ * some custom handling of the state change.
+ */
+static void notify_message(char *mailbox_full, int thereornot)
+{
+ char s[sizeof(mwimonitornotify) + 80];
+ struct ast_event *event;
+ char *mailbox, *context;
+
+ /* Strip off @default */
+ context = mailbox = ast_strdupa(mailbox_full);
+ strsep(&context, "@");
+ if (ast_strlen_zero(context))
+ context = "default";
+
+ if (!(event = ast_event_new(AST_EVENT_MWI,
+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
+ AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+ AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+ AST_EVENT_IE_END))) {
+ return;
+ }
+
+ ast_event_queue_and_cache(event);
+
+ if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
+ snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
+ ast_safe_system(s);
+ }
+}
+
+static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
+{
+ struct dahdi_pvt *p = pvt;
+
+ if (neon_mwievent > -1 && !p->mwimonitor_neon)
+ return;
+
+ if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
+ ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
+ notify_message(p->mailbox, 1);
+ } else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
+ ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
+ notify_message(p->mailbox, 0);
+ }
+ /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
+ /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
+ if (neon_mwievent == -1 && p->mwimonitor_rpas) {
+ ast_hangup(chan);
+ return;
+ }
+}
+
+
+static const char *event2str(int event);
+
+static struct analog_callback dahdi_analog_callbacks =
+{
+ .play_tone = my_play_tone,
+ .get_event = my_get_event,
+ .wait_event = my_wait_event,
+ .is_off_hook = my_is_off_hook,
+ .set_echocanceller = my_set_echocanceller,
+ .ring = my_ring,
+ .off_hook = my_off_hook,
+ .dial_digits = my_dial_digits,
+ .train_echocanceller = my_train_echocanceller,
+ .on_hook = my_on_hook,
+ .is_dialing = my_is_dialing,
+ .allocate_sub = my_allocate_sub,
+ .unallocate_sub = my_unallocate_sub,
+ .swap_subs = my_swap_subchannels,
+ .has_voicemail = my_has_voicemail,
+ .check_for_conference = my_check_for_conference,
+ .conf_add = my_conf_add,
+ .conf_del = my_conf_del,
+ .complete_conference_update = my_complete_conference_update,
+ .start = my_start,
+ .all_subchannels_hungup = my_all_subchannels_hungup,
+ .lock_private = my_lock_private,
+ .unlock_private = my_unlock_private,
+ .handle_dtmfup = my_handle_dtmfup,
+ .wink = my_wink,
+ .new_ast_channel = my_new_analog_ast_channel,
+ .dsp_set_digitmode = my_dsp_set_digitmode,
+ .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
+ .send_callerid = my_send_callerid,
+ .callwait = my_callwait,
+ .stop_callwait = my_stop_callwait,
+ .get_callerid = my_get_callerid,
+ .start_cid_detect = my_start_cid_detect,
+ .stop_cid_detect = my_stop_cid_detect,
+ .handle_notify_message = my_handle_notify_message,
+ .increase_ss_count = my_increase_ss_count,
+ .decrease_ss_count = my_decrease_ss_count,
+};
struct dahdi_pvt *round_robin[32];
@@ -2579,6 +3489,45 @@
}
}
+int analog_lib_handles(int signalling, int radio, int oprmode)
+{
+ switch (signalling) {
+ case SIG_FXOLS:
+ case SIG_FXOGS:
+ case SIG_FXOKS:
+ case SIG_FXSLS:
+ case SIG_FXSGS:
+ case SIG_FXSKS:
+ case SIG_EMWINK:
+ case SIG_EM:
+ case SIG_EM_E1:
+ case SIG_FEATD:
+ case SIG_FEATDMF:
+ case SIG_E911:
+ case SIG_FGC_CAMA:
+ case SIG_FGC_CAMAMF:
+ case SIG_FEATB:
+ case SIG_SFWINK:
+ case SIG_SF:
+ case SIG_SF_FEATD:
+ case SIG_SF_FEATDMF:
+ case SIG_FEATDMF_TA:
+ case SIG_SF_FEATB:
+ break;
+ default:
+ /* The rest of the function should cover the remainder of signalling types */
+ return 0;
+ }
+
+ if (radio)
+ return 0;
+
+ if (oprmode)
+ return 0;
+
+ return 1;
+}
+
#define sig2str dahdi_sig2str
static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
@@ -3025,53 +3974,6 @@
return 0;
}
-/*!
- * \brief Send MWI state change
- *
- * \arg mailbox_full This is the mailbox associated with the FXO line that the
- * MWI state has changed on.
- * \arg thereornot This argument should simply be set to 1 or 0, to indicate
- * whether there are messages waiting or not.
- *
- * \return nothing
- *
- * This function does two things:
- *
- * 1) It generates an internal Asterisk event notifying any other module that
- * cares about MWI that the state of a mailbox has changed.
- *
- * 2) It runs the script specified by the mwimonitornotify option to allow
- * some custom handling of the state change.
- */
-static void notify_message(char *mailbox_full, int thereornot)
-{
- char s[sizeof(mwimonitornotify) + 80];
- struct ast_event *event;
- char *mailbox, *context;
-
- /* Strip off @default */
- context = mailbox = ast_strdupa(mailbox_full);
- strsep(&context, "@");
- if (ast_strlen_zero(context))
- context = "default";
-
- if (!(event = ast_event_new(AST_EVENT_MWI,
- AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
- AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
- AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
- AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
- AST_EVENT_IE_END))) {
- return;
- }
-
- ast_event_queue_and_cache(event);
-
- if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
- snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
- ast_safe_system(s);
- }
-}
-
static int restore_conference(struct dahdi_pvt *p)
{
int res;
@@ -3128,6 +4030,8 @@
set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
+
+ /* If this is analog signalling we can exit here */
+ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+ p->callwaitrings = 0;
+ res = analog_call(p->sig_pvt, ast, rdest, timeout);
+ ast_mutex_unlock(&p->lock);
+ return res;
+ }
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum