memory leaks: Memory leak cleanup patch by Corey Farrell (second set)
[asterisk/asterisk.git] / channels / chan_dahdi.c
index 0806ca5..b682994 100644 (file)
@@ -62,6 +62,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #else
 #include <sys/signal.h>
 #endif
+#include <sys/stat.h>
 #include <math.h>
 
 #include "sig_analog.h"
@@ -101,6 +102,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/callerid.h"
 #include "asterisk/adsi.h"
 #include "asterisk/cli.h"
+#include "asterisk/pickup.h"
 #include "asterisk/features.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/say.h"
@@ -117,14 +119,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/abstract_jb.h"
 #include "asterisk/smdi.h"
 #include "asterisk/astobj.h"
-#include "asterisk/event.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/paths.h"
 #include "asterisk/ccss.h"
 #include "asterisk/data.h"
 #include "asterisk/features_config.h"
-#include "asterisk/bridging.h"
+#include "asterisk/bridge.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/parking.h"
 #include "chan_dahdi.h"
 #include "dahdi/bridge_native_dahdi.h"
 
@@ -361,7 +363,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                <managerEventInstance class="EVENT_FLAG_CALL">
                        <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
                        <syntax>
-                               <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+                               <channel_snapshot/>
                                <parameter name="DAHDISpan">
                                        <para>The DAHDI span associated with this channel.</para>
                                </parameter>
@@ -458,6 +460,8 @@ static const char config[] = "chan_dahdi.conf";
 static int num_cadence = 4;
 static int user_has_defined_cadences = 0;
 
+static int has_pseudo;
+
 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
        { { 125, 125, 2000, 4000 } },                   /*!< Quick chirp followed by normal ring */
        { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
@@ -505,7 +509,7 @@ static int mwilevel = 512;
 static int dtmfcid_level = 256;
 
 #define REPORT_CHANNEL_ALARMS 1
-#define REPORT_SPAN_ALARMS    2 
+#define REPORT_SPAN_ALARMS    2
 static int report_alarms = REPORT_CHANNEL_ALARMS;
 
 #ifdef HAVE_PRI
@@ -549,7 +553,7 @@ static int restart_monitor(void);
 
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
+static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        /* This module does not handle MWI in an event-based manner.  However, it
         * subscribes to MWI for each mailbox that is configured so that the core
@@ -814,6 +818,18 @@ struct dahdi_chan_conf {
         * \note Set from the "smdiport" string read in from chan_dahdi.conf
         */
        char smdi_port[SMDI_MAX_FILENAME_LEN];
+
+       /*!
+        * \brief Don't create channels below this number
+        * \note by default is 0 (no limit)
+        */
+       int wanted_channels_start;
+
+       /*!
+        * \brief Don't create channels above this number (infinity by default)
+        * \note by default is 0 (special value that means "no limit").
+        */
+       int wanted_channels_end;
 };
 
 /*! returns a new dahdi_chan_conf with default values (by-value) */
@@ -1704,14 +1720,14 @@ static void my_ami_channel_event(void *pvt, struct ast_channel *chan)
 #endif
 
 /* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on
-*      returns the last value of the linear setting 
-*/ 
+*      returns the last value of the linear setting
+*/
 static int my_set_linear_mode(void *pvt, enum analog_sub sub, int linear_mode)
 {
        struct dahdi_pvt *p = pvt;
        int oldval;
        int idx = analogsub_to_dahdisub(sub);
-       
+
        dahdi_setlinear(p->subs[idx].dfd, linear_mode);
        oldval = p->subs[idx].linear;
        p->subs[idx].linear = linear_mode ? 1 : 0;
@@ -1739,12 +1755,12 @@ static void my_get_and_handle_alarms(void *pvt)
 
 static void *my_get_sigpvt_bridged_channel(struct ast_channel *chan)
 {
-       struct ast_channel *bridged = ast_bridged_channel(chan);
+       RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(chan), ast_channel_cleanup);
 
        if (bridged && ast_channel_tech(bridged) == &dahdi_tech) {
                struct dahdi_pvt *p = ast_channel_tech_pvt(bridged);
 
-               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                        return p->sig_pvt;
                }
        }
@@ -2429,9 +2445,9 @@ static int my_set_echocanceller(void *pvt, int enable)
        struct dahdi_pvt *p = pvt;
 
        if (enable)
-               dahdi_enable_ec(p);
+               dahdi_ec_enable(p);
        else
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
 
        return 0;
 }
@@ -2630,7 +2646,7 @@ static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
 #endif /* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
-static int pri_destroy_dchan(struct sig_pri_span *pri);
+static void pri_destroy_span(struct sig_pri_span *pri);
 
 static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
 {
@@ -2660,7 +2676,7 @@ static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
                pri_event_noalarm(pri, index, 0);
                break;
        case DAHDI_EVENT_REMOVED:
-               pri_destroy_dchan(pri);
+               pri_destroy_span(pri);
                break;
        default:
                break;
@@ -3578,7 +3594,7 @@ static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t
        struct ast_callid *callid = NULL;
        int callid_created = ast_callid_threadstorage_auto(&callid);
        p = openr2_chan_get_client_data(r2chan);
-       dahdi_enable_ec(p);
+       dahdi_ec_enable(p);
        p->mfcr2_call_accepted = 1;
        /* if it's an incoming call ... */
        if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
@@ -3670,6 +3686,7 @@ static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disco
        snprintf(cause_str, sizeof(cause_str), "R2 DISCONNECT (%s)", openr2_proto_get_disconnect_string(cause));
        datalen += strlen(cause_str);
        cause_code = ast_alloca(datalen);
+       memset(cause_code, 0, datalen);
        cause_code->ast_cause = dahdi_r2_cause_to_ast_cause(cause);
        ast_copy_string(cause_code->chan_name, ast_channel_name(p->owner), AST_CHANNEL_NAME);
        ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
@@ -4364,7 +4381,7 @@ static int reset_conf(struct dahdi_pvt *p)
        return 0;
 }
 
-void update_conf(struct dahdi_pvt *p)
+void dahdi_conf_update(struct dahdi_pvt *p)
 {
        int needconf = 0;
        int x;
@@ -4419,7 +4436,7 @@ void update_conf(struct dahdi_pvt *p)
        ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
 }
 
-void dahdi_enable_ec(struct dahdi_pvt *p)
+void dahdi_ec_enable(struct dahdi_pvt *p)
 {
        int res;
        if (!p)
@@ -4491,7 +4508,7 @@ static void dahdi_train_ec(struct dahdi_pvt *p)
        }
 }
 
-void dahdi_disable_ec(struct dahdi_pvt *p)
+void dahdi_ec_disable(struct dahdi_pvt *p)
 {
        int res;
 
@@ -4509,13 +4526,22 @@ void dahdi_disable_ec(struct dahdi_pvt *p)
        p->echocanon = 0;
 }
 
+static int set_hwgain(int fd, float gain, int tx_direction)
+{
+       struct dahdi_hwgain hwgain;
+
+       hwgain.newgain = gain * 10.0;
+       hwgain.tx = tx_direction;
+       return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
+}
+
 /* perform a dynamic range compression transform on the given sample */
 static int drc_sample(int sample, float drc)
 {
        float neg;
        float shallow, steep;
        float max = SHRT_MAX;
-       
+
        neg = (sample < 0 ? -1 : 1);
        steep = drc*sample;
        shallow = neg*(max-max/drc)+(float)sample/drc;
@@ -4821,7 +4847,7 @@ static int has_voicemail(struct dahdi_pvt *p)
        }
 
        ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
-       mwi_message = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
+       mwi_message = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
 
        if (mwi_message) {
                struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
@@ -4973,7 +4999,7 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
                set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, p->rxdrc, p->txdrc, p->law);
        } else {
                set_actual_gain(p->subs[SUB_REAL].dfd, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law);
-       }       
+       }
 
 #ifdef HAVE_PRI
        if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -4993,7 +5019,7 @@ static int dahdi_call(struct ast_channel *ast, const char *rdest, int timeout)
 #endif /* defined(HAVE_SS7) */
 
        /* If this is analog signalling we can exit here */
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_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);
@@ -5344,7 +5370,7 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
        }
 
        if (p->sig_pvt) {
-               if (analog_lib_handles(p->sig, 0, 0)) {
+               if (dahdi_analog_lib_handles(p->sig, 0, 0)) {
                        analog_delete(p->sig_pvt);
                }
                switch (p->sig) {
@@ -5747,7 +5773,7 @@ static int dahdi_hangup(struct ast_channel *ast)
 
        ast_mutex_lock(&p->lock);
        p->exten[0] = '\0';
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                dahdi_confmute(p, 0);
                restore_gains(p);
                p->ignoredtmf = 0;
@@ -5805,14 +5831,14 @@ static int dahdi_hangup(struct ast_channel *ast)
                sig_pri_hangup(p->sig_pvt, ast);
 
                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
 
                x = 0;
                ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
                p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
 
                p->rdnis[0] = '\0';
-               update_conf(p);
+               dahdi_conf_update(p);
                reset_conf(p);
 
                /* Restore data mode */
@@ -5867,13 +5893,13 @@ static int dahdi_hangup(struct ast_channel *ast)
                sig_ss7_hangup(p->sig_pvt, ast);
 
                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
 
                x = 0;
                ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
                p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
 
-               update_conf(p);
+               dahdi_conf_update(p);
                reset_conf(p);
 
                /* Restore data mode */
@@ -6094,7 +6120,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                        break;
                }
                if (p->sig)
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                x = 0;
                ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
                ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
@@ -6105,7 +6131,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                p->waitingfordt.tv_sec = 0;
                p->dialing = 0;
                p->rdnis[0] = '\0';
-               update_conf(p);
+               dahdi_conf_update(p);
                reset_conf(p);
                /* Restore data mode */
                switch (p->sig) {
@@ -6163,7 +6189,7 @@ static int dahdi_answer(struct ast_channel *ast)
                return 0;
        }
 
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                res = analog_answer(p->sig_pvt, ast);
                ast_mutex_unlock(&p->lock);
                return res;
@@ -6211,7 +6237,7 @@ static int dahdi_answer(struct ast_channel *ast)
        return res;
 }
 
-void disable_dtmf_detect(struct dahdi_pvt *p)
+void dahdi_dtmf_detect_disable(struct dahdi_pvt *p)
 {
        int val = 0;
 
@@ -6225,7 +6251,7 @@ void disable_dtmf_detect(struct dahdi_pvt *p)
        }
 }
 
-void enable_dtmf_detect(struct dahdi_pvt *p)
+void dahdi_dtmf_detect_enable(struct dahdi_pvt *p)
 {
        int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
 
@@ -6350,7 +6376,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                }
                ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
                        (*cp == 2) ? "MATE" : "ON", (int) *cp, ast_channel_name(chan));
-               dahdi_disable_ec(p);
+               dahdi_ec_disable(p);
                /* otherwise, turn it on */
                if (!p->didtdd) { /* if havent done it yet */
                        unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
@@ -6432,7 +6458,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                if (!*cp) {
                        ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", ast_channel_name(chan));
                        x = 0;
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                } else {
                        ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", ast_channel_name(chan));
                        x = 1;
@@ -6467,19 +6493,19 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                cp = (char *) data;
                if (*cp) {
                        ast_debug(1, "Enabling echo cancellation on %s\n", ast_channel_name(chan));
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                } else {
                        ast_debug(1, "Disabling echo cancellation on %s\n", ast_channel_name(chan));
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                }
                break;
        case AST_OPTION_DIGIT_DETECT:
                cp = (char *) data;
                ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", ast_channel_name(chan));
                if (*cp) {
-                       enable_dtmf_detect(p);
+                       dahdi_dtmf_detect_enable(p);
                } else {
-                       disable_dtmf_detect(p);
+                       dahdi_dtmf_detect_disable(p);
                }
                break;
        case AST_OPTION_FAX_DETECT:
@@ -6674,11 +6700,11 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
        } else if (!strcasecmp(data, "echocan_mode")) {
                if (!strcasecmp(value, "on")) {
                        ast_mutex_lock(&p->lock);
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                        ast_mutex_unlock(&p->lock);
                } else if (!strcasecmp(value, "off")) {
                        ast_mutex_lock(&p->lock);
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                        ast_mutex_unlock(&p->lock);
 #ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
                } else if (!strcasecmp(value, "fax")) {
@@ -6686,7 +6712,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 
                        ast_mutex_lock(&p->lock);
                        if (!p->echocanon) {
-                               dahdi_enable_ec(p);
+                               dahdi_ec_enable(p);
                        }
                        if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
                                ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
@@ -6697,7 +6723,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 
                        ast_mutex_lock(&p->lock);
                        if (!p->echocanon) {
-                               dahdi_enable_ec(p);
+                               dahdi_ec_enable(p);
                        }
                        if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
                                ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
@@ -6715,7 +6741,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
        return res;
 }
 
-void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
+void dahdi_master_slave_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
 {
        /* Unlink a specific slave or all slaves/masters from a given master */
        int x;
@@ -6763,7 +6789,7 @@ void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needloc
                }
                master->master = NULL;
        }
-       update_conf(master);
+       dahdi_conf_update(master);
        if (needlock) {
                if (slave)
                        ast_mutex_unlock(&slave->lock);
@@ -6771,7 +6797,7 @@ void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needloc
        }
 }
 
-void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
+void dahdi_master_slave_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
 {
        int x;
        if (!slave || !master) {
@@ -6809,12 +6835,12 @@ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        for (x = 0; x < 3; x++) {
                if (p->subs[x].owner == oldchan) {
                        if (!x) {
-                               dahdi_unlink(NULL, p, 0);
+                               dahdi_master_slave_unlink(NULL, p, 0);
                        }
                        p->subs[x].owner = newchan;
                }
        }
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                analog_fixup(oldchan, newchan, p->sig_pvt);
 #if defined(HAVE_PRI)
        } else if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -6825,7 +6851,7 @@ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
                sig_ss7_fixup(oldchan, newchan, p->sig_pvt);
 #endif /* defined(HAVE_SS7) */
        }
-       update_conf(p);
+       dahdi_conf_update(p);
 
        ast_mutex_unlock(&p->lock);
 
@@ -7268,7 +7294,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                        return NULL;
                }
                if (!x) { /* if not still dialing in driver */
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                        if (p->echobreak) {
                                dahdi_train_ec(p);
                                ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
@@ -7463,7 +7489,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                        }
                        /* Fall through */
                default:
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                        return NULL;
                }
                break;
@@ -7518,7 +7544,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                case SIG_FXOKS:
                        switch (ast_channel_state(ast)) {
                        case AST_STATE_RINGING:
-                               dahdi_enable_ec(p);
+                               dahdi_ec_enable(p);
                                dahdi_train_ec(p);
                                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
                                p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
@@ -7786,7 +7812,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        /* Swap things around between the three-way and real call */
                                        swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                        /* Disable echo canceller for better dialing */
-                                       dahdi_disable_ec(p);
+                                       dahdi_ec_disable(p);
                                        res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
                                        if (res)
                                                ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
@@ -7796,7 +7822,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                        } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
                                                ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
                                                res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
-                                               dahdi_enable_ec(p);
+                                               dahdi_ec_enable(p);
                                                ast_hangup(chan);
                                        } else {
                                                ast_verb(3, "Started three way call on channel %d\n", p->channel);
@@ -7853,12 +7879,12 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                                                        ast_queue_unhold(p->subs[SUB_REAL].owner);
                                                }
                                                p->subs[SUB_REAL].needunhold = 1;
-                                               dahdi_enable_ec(p);
+                                               dahdi_ec_enable(p);
                                        }
                                }
                        }
 winkflashdone:
-                       update_conf(p);
+                       dahdi_conf_update(p);
                        break;
                case SIG_EM:
                case SIG_EM_E1:
@@ -8051,7 +8077,7 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                }
                switch (res) {
                case DAHDI_EVENT_ONHOOK:
-                       dahdi_disable_ec(p);
+                       dahdi_ec_disable(p);
                        if (p->owner) {
                                ast_verb(3, "Channel %s still has call, ringing phone\n", ast_channel_name(p->owner));
                                dahdi_ring_phone(p);
@@ -8060,10 +8086,10 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                                p->cid_suppress_expire = 0;
                        } else
                                ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
-                       update_conf(p);
+                       dahdi_conf_update(p);
                        break;
                case DAHDI_EVENT_RINGOFFHOOK:
-                       dahdi_enable_ec(p);
+                       dahdi_ec_enable(p);
                        dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
                        if (p->owner && (ast_channel_state(p->owner) == AST_STATE_RINGING)) {
                                p->subs[SUB_REAL].needanswer = 1;
@@ -8094,7 +8120,7 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
                                p->subs[SUB_REAL].needunhold = 1;
                        } else
                                ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
-                       update_conf(p);
+                       dahdi_conf_update(p);
                        break;
                default:
                        ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
@@ -8132,7 +8158,7 @@ static struct ast_frame *dahdi_exception(struct ast_channel *ast)
        struct dahdi_pvt *p = ast_channel_tech_pvt(ast);
        struct ast_frame *f;
        ast_mutex_lock(&p->lock);
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                struct analog_pvt *analog_p = p->sig_pvt;
                f = analog_exception(analog_p, ast);
        } else {
@@ -8238,7 +8264,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                        /* if the call is already accepted and we already delivered AST_CONTROL_RINGING
                         * now enqueue a progress frame to bridge the media up */
                        if (p->mfcr2_call_accepted &&
-                               !p->mfcr2_progress_sent && 
+                               !p->mfcr2_progress_sent &&
                                ast_channel_state(ast) == AST_STATE_RINGING) {
                                ast_debug(1, "Enqueuing progress frame after R2 accept in chan %d\n", p->channel);
                                ast_queue_frame(p->owner, &fr);
@@ -8329,7 +8355,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
         * if this channel owns the private.
         */
        if (p->fake_event && p->owner == ast) {
-               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                        struct analog_pvt *analog_p = p->sig_pvt;
 
                        f = analog_exception(analog_p, ast);
@@ -8373,7 +8399,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                ast_mutex_unlock(&p->lock);
                                return &p->subs[idx].f;
                        } else if (errno == ELAST) {
-                               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                                        struct analog_pvt *analog_p = p->sig_pvt;
                                        f = analog_exception(analog_p, ast);
                                } else {
@@ -8387,7 +8413,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
        }
        if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
                ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+               if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                        struct analog_pvt *analog_p = p->sig_pvt;
                        f = analog_exception(analog_p, ast);
                } else {
@@ -8565,7 +8591,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                switch (f->frametype) {
                case AST_FRAME_DTMF_BEGIN:
                case AST_FRAME_DTMF_END:
-                       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                                analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
                        } else {
                                dahdi_handle_dtmf(ast, idx, &f);
@@ -8893,6 +8919,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
                return NULL;
        }
 
+       ast_channel_stage_snapshot(tmp);
+
        if (callid) {
                ast_channel_callid_set(tmp, callid);
        }
@@ -9013,7 +9041,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
                ast_channel_amaflags_set(tmp, i->amaflags);
        i->subs[idx].owner = tmp;
        ast_channel_context_set(tmp, i->context);
-       if (!analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+       if (!dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
                ast_channel_call_forward_set(tmp, i->call_forward);
        }
        /* If we've been told "no ADSI" then enforce it */
@@ -9070,6 +9098,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        for (v = i->vars ; v ; v = v->next)
                pbx_builtin_setvar_helper(tmp, v->name, v->value);
 
+       ast_channel_stage_snapshot_done(tmp);
+
        ast_module_ref(ast_module_info->self);
 
        dahdi_ami_channel_event(i, tmp);
@@ -9157,7 +9187,7 @@ static void publish_dnd_state(int channel, const char *status)
  */
 static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
 {
-       if (analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
+       if (dahdi_analog_lib_handles(dahdichan->sig, dahdichan->radio, dahdichan->oprmode)) {
                return analog_dnd(dahdichan->sig_pvt, flag);
        }
 
@@ -9494,7 +9524,7 @@ static void *analog_ss_thread(void *data)
                                goto quit;
                        }
                }
-               dahdi_enable_ec(p);
+               dahdi_ec_enable(p);
                if (NEED_MFDETECT(p)) {
                        if (p->dsp) {
                                if (!p->hardwaredtmf)
@@ -9542,6 +9572,8 @@ static void *analog_ss_thread(void *data)
                if (p->subs[SUB_THREEWAY].owner)
                        timeout = 999999;
                while (len < AST_MAX_EXTENSION-1) {
+                       int is_exten_parking = 0;
+
                        /* Read digit unless it's supposed to be immediate, in which case the
                           only answer is 's' */
                        if (p->immediate)
@@ -9559,11 +9591,15 @@ static void *analog_ss_thread(void *data)
                                exten[len++]=res;
                                exten[len] = '\0';
                        }
-                       if (!ast_ignore_pattern(ast_channel_context(chan), exten))
+                       if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
                                tone_zone_play_tone(p->subs[idx].dfd, -1);
-                       else
+                       } else {
                                tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
-                       if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, ast_channel_context(chan))) {
+                       }
+                       if (ast_parking_provider_registered()) {
+                               is_exten_parking = ast_parking_is_exten_park(ast_channel_context(chan), exten);
+                       }
+                       if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
                                if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
                                        if (getforward) {
                                                /* Record this as the forwarding extension */
@@ -9593,7 +9629,7 @@ static void *analog_ss_thread(void *data)
                                                                ast_set_callerid(chan, NULL, p->cid_name, NULL);
                                                }
                                                ast_setstate(chan, AST_STATE_RING);
-                                               dahdi_enable_ec(p);
+                                               dahdi_ec_enable(p);
                                                res = ast_pbx_run(chan);
                                                if (res) {
                                                        ast_log(LOG_WARNING, "PBX exited non-zero\n");
@@ -9640,7 +9676,7 @@ static void *analog_ss_thread(void *data)
                                                swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
                                                unalloc_sub(p, SUB_THREEWAY);
                                        }
-                                       dahdi_enable_ec(p);
+                                       dahdi_ec_enable(p);
                                        if (ast_pickup_call(chan)) {
                                                ast_debug(1, "No call pickup possible...\n");
                                                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
@@ -9699,14 +9735,35 @@ static void *analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, ast_channel_context(chan)) &&
-                                               p->subs[SUB_THREEWAY].owner &&
-                                               ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-                               /* This is a three way call, the main call being a real channel,
-                                       and we're parking the first call. */
-                               ast_masq_park_call_exten(ast_bridged_channel(p->subs[SUB_THREEWAY].owner),
-                                       chan, exten, ast_channel_context(chan), 0, NULL);
-                               ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+                       } else if ((p->transfer || p->canpark) && is_exten_parking
+                               && p->subs[SUB_THREEWAY].owner) {
+                               struct ast_bridge_channel *bridge_channel;
+
+                               /*
+                                * This is a three way call, the main call being a real channel,
+                                * and we're parking the first call.
+                                */
+                               ast_channel_lock(p->subs[SUB_THREEWAY].owner);
+                               bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
+                               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+                               if (bridge_channel) {
+                                       if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+                                               /*
+                                                * Swap things around between the three-way and real call so we
+                                                * can hear where the channel got parked.
+                                                */
+                                               ast_mutex_lock(&p->lock);
+                                               p->owner = p->subs[SUB_THREEWAY].owner;
+                                               swap_subs(p, SUB_THREEWAY, SUB_REAL);
+                                               ast_mutex_unlock(&p->lock);
+
+                                               ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
+                                               ast_hangup(chan);
+                                               ao2_ref(bridge_channel, -1);
+                                               goto quit;
+                                       }
+                                       ao2_ref(bridge_channel, -1);
+                               }
                                break;
                        } else if (p->hidecallerid && !strcmp(exten, "*82")) {
                                ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
@@ -9725,12 +9782,15 @@ static void *analog_ss_thread(void *data)
                                struct ast_channel *nbridge =
                                        p->subs[SUB_THREEWAY].owner;
                                struct dahdi_pvt *pbridge = NULL;
+                               RAII_VAR(struct ast_channel *, bridged, nbridge ? ast_channel_bridge_peer(nbridge) : NULL, ast_channel_cleanup);
+
                                /* set up the private struct of the bridged one, if any */
-                               if (nbridge && ast_bridged_channel(nbridge))
-                                       pbridge = ast_channel_tech_pvt(ast_bridged_channel(nbridge));
+                               if (nbridge && bridged) {
+                                       pbridge = ast_channel_tech_pvt(bridged);
+                               }
                                if (nbridge && pbridge &&
                                        (ast_channel_tech(nbridge) == &dahdi_tech) &&
-                                       (ast_channel_tech(ast_bridged_channel(nbridge)) == &dahdi_tech) &&
+                                       (ast_channel_tech(bridged) == &dahdi_tech) &&
                                        ISTRUNK(pbridge)) {
                                        int func = DAHDI_FLASH;
                                        /* Clear out the dial buffer */
@@ -10424,7 +10484,7 @@ static void *mwi_thread(void *data)
                        case DAHDI_EVENT_BITSCHANGED:
                                break;
                        case DAHDI_EVENT_NOALARM:
-                               if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+                               if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
                                        struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
 
                                        analog_p->inalarm = 0;
@@ -10433,7 +10493,7 @@ static void *mwi_thread(void *data)
                                handle_clear_alarms(mtd->pvt);
                                break;
                        case DAHDI_EVENT_ALARM:
-                               if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+                               if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
                                        struct analog_pvt *analog_p = mtd->pvt->sig_pvt;
 
                                        analog_p->inalarm = 1;
@@ -10453,7 +10513,7 @@ static void *mwi_thread(void *data)
                                if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, NULL, callid))) {
                                        int result;
 
-                                       if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
+                                       if (dahdi_analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
                                                result = analog_ss_thread_start(mtd->pvt->sig_pvt, chan);
                                        } else {
                                                result = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
@@ -10721,29 +10781,121 @@ static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
        return handled;
 }
 
-/* destroy a DAHDI channel, identified by its number */
-static int dahdi_destroy_channel_bynum(int channel)
+/* destroy a range DAHDI channels, identified by their number */
+static void dahdi_destroy_channel_range(int start, int end)
 {
        struct dahdi_pvt *cur;
+       struct dahdi_pvt *next;
+       int destroyed_first = 0;
+       int destroyed_last = 0;
 
        ast_mutex_lock(&iflock);
-       for (cur = iflist; cur; cur = cur->next) {
-               if (cur->channel == channel) {
+       ast_debug(1, "range: %d-%d\n", start, end);
+       for (cur = iflist; cur; cur = next) {
+               next = cur->next;
+               if (cur->channel >= start && cur->channel <= end) {
                        int x = DAHDI_FLASH;
 
+                       if (cur->channel > destroyed_last) {
+                               destroyed_last = cur->channel;
+                       }
+                       if (destroyed_first < 1 || cur->channel < destroyed_first) {
+                               destroyed_first = cur->channel;
+                       }
+                       ast_debug(3, "Destroying %d\n", cur->channel);
                        /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
                        ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
 
                        destroy_channel(cur, 1);
-                       ast_mutex_unlock(&iflock);
                        ast_module_unref(ast_module_info->self);
-                       return RESULT_SUCCESS;
                }
        }
        ast_mutex_unlock(&iflock);
-       return RESULT_FAILURE;
+       if (destroyed_first > start || destroyed_last < end) {
+               ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
+                       start, end, destroyed_first, destroyed_last);
+       }
 }
 
+static int setup_dahdi(int reload);
+static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
+
+/*!
+ * \internal
+ * \brief create a range of new DAHDI channels
+ *
+ * \param start first channel in the range
+ * \param end last channel in the range
+ *
+ * \retval RESULT_SUCCESS on success.
+ * \retval RESULT_FAILURE on error.
+ */
+static int dahdi_create_channel_range(int start, int end)
+{
+       struct dahdi_pvt *cur;
+       struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
+       struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
+       struct dahdi_chan_conf conf = dahdi_chan_conf_default();
+       int i, x;
+       int ret = RESULT_FAILURE; /* be pessimistic */
+
+       ast_debug(1, "channel range caps: %d - %d\n", start, end);
+       ast_mutex_lock(&iflock);
+       for (cur = iflist; cur; cur = cur->next) {
+               if (cur->channel >= start && cur->channel <= end) {
+                       ast_log(LOG_ERROR,
+                               "channel range %d-%d is occupied\n",
+                               start, end);
+                       goto out;
+               }
+       }
+       for (x = 0; x < NUM_SPANS; x++) {
+#ifdef HAVE_PRI
+               struct dahdi_pri *pri = pris + x;
+
+               if (!pris[x].pri.pvts[0]) {
+                       break;
+               }
+               for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
+                       int channo = pri->dchannels[i];
+
+                       if (!channo) {
+                               break;
+                       }
+                       if (!pri->pri.fds[i]) {
+                               break;
+                       }
+                       if (channo >= start && channo <= end) {
+                               ast_log(LOG_ERROR,
+                                               "channel range %d-%d is occupied by span %d\n",
+                                               start, end, x + 1);
+                               goto out;
+                       }
+               }
+#endif
+       }
+       if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
+               !conf.chan.cc_params) {
+               goto out;
+       }
+       default_conf.wanted_channels_start = start;
+       base_conf.wanted_channels_start = start;
+       conf.wanted_channels_start = start;
+       default_conf.wanted_channels_end = end;
+       base_conf.wanted_channels_end = end;
+       conf.wanted_channels_end = end;
+       if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
+               ret = RESULT_SUCCESS;
+       }
+out:
+       ast_cc_config_params_destroy(default_conf.chan.cc_params);
+       ast_cc_config_params_destroy(base_conf.chan.cc_params);
+       ast_cc_config_params_destroy(conf.chan.cc_params);
+       ast_mutex_unlock(&iflock);
+       return ret;
+}
+
+
 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 {
        int res;
@@ -10780,7 +10932,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                        restore_conference(i);
 
                        if (i->immediate) {
-                               dahdi_enable_ec(i);
+                               dahdi_ec_enable(i);
                                /* The channel is immediately up.  Start right away */
                                res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
                                chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, NULL, callid);
@@ -10929,7 +11081,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                case SIG_FXSGS:
                case SIG_FXSKS:
                case SIG_FXOKS:
-                       dahdi_disable_ec(i);
+                       dahdi_ec_disable(i);
                        /* Diddle the battery for the zhone */
 #ifdef ZHONE_HACK
                        dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
@@ -10940,7 +11092,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
                        break;
                case SIG_SS7:
                case SIG_PRI_LIB_HANDLE_CASES:
-                       dahdi_disable_ec(i);
+                       dahdi_ec_disable(i);
                        res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
                        break;
                default:
@@ -11003,6 +11155,11 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
        return NULL;
 }
 
+static void monitor_pfds_clean(void *arg) {
+       struct pollfd **pfds = arg;
+       ast_free(*pfds);
+}
+
 static void *do_monitor(void *data)
 {
        int count, res, res2, spoint, pollres=0;
@@ -11026,6 +11183,7 @@ static void *do_monitor(void *data)
 #endif
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
+       pthread_cleanup_push(monitor_pfds_clean, &pfds);
        for (;;) {
                /* Lock the interface list */
                ast_mutex_lock(&iflock);
@@ -11048,7 +11206,7 @@ static void *do_monitor(void *data)
                for (i = iflist; i; i = i->next) {
                        ast_mutex_lock(&i->lock);
                        if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
-                               if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+                               if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
                                        struct analog_pvt *p = i->sig_pvt;
 
                                        if (!p) {
@@ -11059,7 +11217,7 @@ static void *do_monitor(void *data)
                                                pfds[count].events = POLLPRI;
                                                pfds[count].revents = 0;
                                                /* Message waiting or r2 channels also get watched for reading */
-                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk || 
+                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
                                                        (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
                                                        pfds[count].events |= POLLIN;
                                                }
@@ -11109,11 +11267,7 @@ static void *do_monitor(void *data)
                doomed = NULL;
                for (i = iflist;; i = i->next) {
                        if (doomed) {
-                               int res;
-                               res = dahdi_destroy_channel_bynum(doomed->channel);
-                               if (res != RESULT_SUCCESS) {
-                                       ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
-                               }
+                               dahdi_destroy_channel_range(doomed->channel, doomed->channel);
                                doomed = NULL;
                        }
                        if (!i) {
@@ -11162,7 +11316,7 @@ static void *do_monitor(void *data)
                                                ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
                                                /* Don't hold iflock while handling init events */
                                                ast_mutex_unlock(&iflock);
-                                               if (analog_lib_handles(i->sig, i->radio, i->oprmode))
+                                               if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
                                                        doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
                                                else
                                                        doomed = handle_init_event(i, res);
@@ -11212,7 +11366,7 @@ static void *do_monitor(void *data)
                                                        int energy;
                                                        struct timeval now;
                                                        /* State machine dtmfcid_holdoff_state allows for the line to settle
-                                                        * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again 
+                                                        * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again
                                                        */
                                                        if (1 == i->dtmfcid_holdoff_state) {
                                                                gettimeofday(&i->dtmfcid_delay, NULL);
@@ -11228,9 +11382,9 @@ static void *do_monitor(void *data)
                                                                        pthread_t threadid;
                                                                        struct ast_channel *chan;
                                                                        ast_mutex_unlock(&iflock);
-                                                                       if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+                                                                       if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
                                                                                /* just in case this event changes or somehow destroys a channel, set doomed here too */
-                                                                               doomed = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);  
+                                                                               doomed = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);
                                                                                i->dtmfcid_holdoff_state = 1;
                                                                        } else {
                                                                                struct ast_callid *callid = NULL;
@@ -11273,7 +11427,7 @@ static void *do_monitor(void *data)
                                        /* Don't hold iflock while handling init events */
                                        ast_mutex_unlock(&iflock);
                                        if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
-                                               if (analog_lib_handles(i->sig, i->radio, i->oprmode))
+                                               if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode))
                                                        doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
                                                else
                                                        doomed = handle_init_event(i, res);
@@ -11285,6 +11439,7 @@ static void *do_monitor(void *data)
                ast_mutex_unlock(&iflock);
        }
        /* Never reached */
+       pthread_cleanup_pop(1);
        return NULL;
 
 }
@@ -11491,9 +11646,9 @@ static struct dahdi_mfcr2 *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
        struct dahdi_mfcr2 *new_r2link = NULL;
        struct dahdi_mfcr2 **new_r2links = NULL;
 
-       /* Only create a new R2 link if 
+       /* Only create a new R2 link if
           1. This is the first link requested
-          2. Configuration changed 
+          2. Configuration changed
           3. We got more channels than supported per link */
        if (!r2links_count ||
            memcmp(&conf->mfcr2, &r2links[r2links_count - 1]->conf, sizeof(conf->mfcr2)) ||
@@ -11742,7 +11897,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                        tmp->sig = chan_sig;
                        tmp->outsigmod = conf->chan.outsigmod;
 
-                       if (analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
+                       if (dahdi_analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
                                analog_p = analog_new(dahdisig_to_analogsig(chan_sig), tmp);
                                if (!analog_p) {
                                        destroy_dahdi_pvt(tmp);
@@ -12256,7 +12411,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
                ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
                tmp->cid_ton = 0;
-               if (analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
+               if (dahdi_analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
                        ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
                        ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
                } else {
@@ -12312,6 +12467,10 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                }
                        }
                }
+               tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
+               tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
+               tmp->hwrxgain = conf->chan.hwrxgain;
+               tmp->hwtxgain = conf->chan.hwtxgain;
                tmp->cid_rxgain = conf->chan.cid_rxgain;
                tmp->rxgain = conf->chan.rxgain;
                tmp->txgain = conf->chan.txgain;
@@ -12319,10 +12478,16 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                tmp->rxdrc = conf->chan.rxdrc;
                tmp->tonezone = conf->chan.tonezone;
                if (tmp->subs[SUB_REAL].dfd > -1) {
+                       if (tmp->hwrxgain_enabled) {
+                               tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
+                       }
+                       if (tmp->hwtxgain_enabled) {
+                               tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
+                       }
                        set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
                        if (tmp->dsp)
                                ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
-                       update_conf(tmp);
+                       dahdi_conf_update(tmp);
                        if (!here) {
                                switch (chan_sig) {
                                case SIG_PRI_LIB_HANDLE_CASES:
@@ -12582,7 +12747,7 @@ static int available(struct dahdi_pvt **pvt, int is_specific_channel)
        if (p->inalarm)
                return 0;
 
-       if (analog_lib_handles(p->sig, p->radio, p->oprmode))
+       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode))
                return analog_available(p->sig_pvt);
 
        switch (p->sig) {
@@ -13088,7 +13253,7 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
                        }
 
                        p->outgoing = 1;
-                       if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                       if (dahdi_analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                                tmp = analog_request(p->sig_pvt, &callwait, requestor);
 #ifdef HAVE_PRI
                        } else if (dahdi_sig_pri_lib_handles(p->sig)) {
@@ -13559,10 +13724,21 @@ static int prepare_pri(struct dahdi_pri *pri)
        for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
                if (!pri->dchannels[i])
                        break;
+               if (pri->pri.fds[i] >= 0) {
+                       /* A partial range addition. Not a complete setup. */
+                       break;
+               }
                pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
+               if ((pri->pri.fds[i] < 0)) {
+                       ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
+                               pri->pri.fds[i], strerror(errno));
+                       return -1;
+               }
                x = pri->dchannels[i];
-               if ((pri->pri.fds[i] < 0) || (ioctl(pri->pri.fds[i],DAHDI_SPECIFY,&x) == -1)) {
-                       ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
+               res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
+               if (res) {
+                       dahdi_close_pri_fd(pri, i);
+                       ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
                        return -1;
                }
                memset(&p, 0, sizeof(p));
@@ -13963,22 +14139,45 @@ static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_
  *
  * \param pri the pri span
  *
- * \return TRUE if the span was valid and we attempted destroying.
- *
  * Shuts down a span and destroys its D-Channel. Further destruction
  * of the B-channels using dahdi_destroy_channel() would probably be required
  * for the B-Channels.
  */
-static int pri_destroy_dchan(struct sig_pri_span *pri)
+static void pri_destroy_span(struct sig_pri_span *pri)
 {
        int i;
+       int res;
+       int cancel_code;
        struct dahdi_pri* dahdi_pri;
+       pthread_t master = pri->master;
 
-       if (!pri->master || (pri->master == AST_PTHREADT_NULL)) {
-               return 0;
+       if (!master || (master == AST_PTHREADT_NULL)) {
+               return;
+       }
+       ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
+       for (i = 0; i < pri->numchans; i++) {
+               int channel;
+               struct sig_pri_chan *pvt = pri->pvts[i];
+
+               if (!pvt) {
+                       continue;
+               }
+               channel = pvt->channel;
+               ast_debug(2, "About to destroy B-channel %d.\n", channel);
+               dahdi_destroy_channel_range(channel, channel);
+       }
+
+       cancel_code = pthread_cancel(master);
+       pthread_kill(master, SIGURG);
+       ast_debug(4,
+               "Waiting to join thread of span %d "
+               "with pid=%p cancel_code=%d\n",
+               pri->span, (void *)master, cancel_code);
+       res = pthread_join(master, NULL);
+       if (res != 0) {
+               ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
        }
-       pthread_cancel(pri->master);
-       pthread_join(pri->master, NULL);
+       pri->master = AST_PTHREADT_NULL;
 
        /* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
        dahdi_pri = container_of(pri, struct dahdi_pri, pri);
@@ -13986,17 +14185,16 @@ static int pri_destroy_dchan(struct sig_pri_span *pri)
                ast_debug(4, "closing pri_fd %d\n", i);
                dahdi_close_pri_fd(dahdi_pri, i);
        }
-       pri->pri = NULL;
+       sig_pri_init_pri(pri);
        ast_debug(1, "PRI span %d destroyed\n", pri->span);
-       return 1;
 }
 
 static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
                struct ast_cli_args *a)
 {
        int span;
-       int i;
        int res;
+       struct sig_pri_span *pri;
 
        switch (cmd) {
        case CLI_INIT:
@@ -14020,25 +14218,13 @@ static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
                        a->argv[3], 1, NUM_SPANS);
                return CLI_SUCCESS;
        }
-       if (!pris[span - 1].pri.pri) {
+       pri = &pris[span - 1].pri;
+       if (!pri->pri) {
                ast_cli(a->fd, "No PRI running on span %d\n", span);
                return CLI_SUCCESS;
        }
 
-       for (i = 0; i < pris[span - 1].pri.numchans; i++) {
-               int channel;
-               struct sig_pri_chan *pvt = pris[span - 1].pri.pvts[i];
-
-               if (!pvt) {
-                       continue;
-               }
-               channel = pvt->channel;
-               ast_debug(2, "About to destroy B-channel %d.\n", channel);
-               dahdi_destroy_channel_bynum(channel);
-       }
-       ast_debug(2, "About to destroy D-channel of span %d.\n", span);
-       pri_destroy_dchan(&pris[span - 1].pri);
-
+       pri_destroy_span(pri);
        return CLI_SUCCESS;
 }
 
@@ -14490,26 +14676,97 @@ static struct ast_cli_entry dahdi_mfcr2_cli[] = {
 
 #endif /* HAVE_OPENR2 */
 
-static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       int channel;
-       int ret;
+       int start;
+       int end;
        switch (cmd) {
        case CLI_INIT:
-               e->command = "dahdi destroy channel";
+               e->command = "dahdi destroy channels";
                e->usage =
-                       "Usage: dahdi destroy channel <chan num>\n"
+                       "Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
                        "       DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
                return NULL;
        case CLI_GENERATE:
                return NULL;
        }
-       if (a->argc != 4)
+       if ((a->argc < 4) || a->argc > 5) {
                return CLI_SHOWUSAGE;
+       }
+       start = atoi(a->argv[3]);
+       if (start < 1) {
+               ast_cli(a->fd, "Invalid starting channel number %s.\n",
+                               a->argv[4]);
+               return CLI_FAILURE;
+       }
+       if (a->argc == 5) {
+               end = atoi(a->argv[4]);
+               if (end < 1) {
+                       ast_cli(a->fd, "Invalid ending channel number %s.\n",
+                                       a->argv[4]);
+                       return CLI_FAILURE;
+               }
+       } else {
+               end = start;
+       }
 
-       channel = atoi(a->argv[3]);
-       ret = dahdi_destroy_channel_bynum(channel);
-       return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
+       if (end < start) {
+               ast_cli(a->fd,
+                       "range end (%d) is smaller than range start (%d)\n",
+                       end, start);
+               return CLI_FAILURE;
+       }
+       dahdi_destroy_channel_range(start, end);
+       return CLI_SUCCESS;
+}
+
+static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       int start;
+       int end;
+       int ret;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "dahdi create channels";
+               e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
+                          "       dahdi create channels new           - add channels not yet created\n"
+                          "For ISDN  and SS7 the range should include complete spans.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+       if ((a->argc < 4) || a->argc > 5) {
+               return CLI_SHOWUSAGE;
+       }
+       if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
+               ret = dahdi_create_channel_range(0, 0);
+               return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
+       }
+       start = atoi(a->argv[3]);
+       if (start <= 0) {
+               ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
+                               a->argv[3]);
+               return CLI_FAILURE;
+       }
+       if (a->argc == 5) {
+               end = atoi(a->argv[4]);
+               if (end <= 0) {
+                       ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
+                                       a->argv[4]);
+                       return CLI_FAILURE;
+               }
+       } else {
+               end = start;
+       }
+       if (end < start) {
+               ast_cli(a->fd,
+                       "range end (%d) is smaller than range start (%d)\n",
+                       end, start);
+               return CLI_FAILURE;
+       }
+       ret = dahdi_create_channel_range(start, end);
+       return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
 }
 
 static void dahdi_softhangup_all(void)
@@ -14540,7 +14797,6 @@ retry:
        ast_mutex_unlock(&iflock);
 }
 
-static int setup_dahdi(int reload);
 static int dahdi_restart(void)
 {
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
@@ -14780,6 +15036,8 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
        struct dahdi_confinfo ci;
        struct dahdi_params ps;
        int x;
+       char hwrxgain[15];
+       char hwtxgain[15];
 
        switch (cmd) {
        case CLI_INIT:
@@ -14853,7 +15111,18 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
                        ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
                        ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
                        ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
-                       ast_cli(a->fd, "Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
+                       if (tmp->hwrxgain_enabled) {
+                               snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
+                       } else {
+                               ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
+                       }
+                       if (tmp->hwtxgain_enabled) {
+                               snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
+                       } else {
+                               ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
+                       }
+                       ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
+                       ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
                        ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
                        ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
                        ast_cli(a->fd, "Echo Cancellation:\n");
@@ -15119,22 +15388,26 @@ static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli
 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        int channel;
-       int gain;
+       float gain;
        int tx;
-       struct dahdi_hwgain hwgain;
        struct dahdi_pvt *tmp = NULL;
 
        switch (cmd) {
        case CLI_INIT:
-               e->command = "dahdi set hwgain";
+               e->command = "dahdi set hwgain {rx|tx}";
                e->usage =
                        "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
-                       "       Sets the hardware gain on a a given channel, overriding the\n"
-                       "   value provided at module loadtime, whether the channel is in\n"
-                       "   use or not.  Changes take effect immediately.\n"
+                       "   Sets the hardware gain on a given channel and overrides the\n"
+                       "   value provided at module loadtime.  Changes take effect\n"
+                       "   immediately whether the channel is in use or not.\n"
+                       "\n"
                        "   <rx|tx> which direction do you want to change (relative to our module)\n"
                        "   <chan num> is the channel number relative to the device\n"
-                       "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
+                       "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
+                       "\n"
+                       "   Please note:\n"
+                       "   * hwgain is only supportable by hardware with analog ports because\n"
+                       "     hwgain works on the analog side of an analog-digital conversion.\n";
                return NULL;
        case CLI_GENERATE:
                return NULL;
@@ -15151,7 +15424,7 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                return CLI_SHOWUSAGE;
 
        channel = atoi(a->argv[4]);
-       gain = atof(a->argv[5])*10.0;
+       gain = atof(a->argv[5]);
 
        ast_mutex_lock(&iflock);
 
@@ -15163,15 +15436,21 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                if (tmp->subs[SUB_REAL].dfd == -1)
                        break;
 
-               hwgain.newgain = gain;
-               hwgain.tx = tx;
-               if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
+               if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
                        ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
                        ast_mutex_unlock(&iflock);
                        return CLI_FAILURE;
                }
-               ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
-                       tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
+               ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
+                       tx ? "tx" : "rx", gain, channel);
+
+               if (tx) {
+                       tmp->hwtxgain_enabled = 1;
+                       tmp->hwtxgain = gain;
+               } else {
+                       tmp->hwrxgain_enabled = 1;
+                       tmp->hwrxgain = gain;
+               }
                break;
        }
 
@@ -15195,12 +15474,13 @@ static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 
        switch (cmd) {
        case CLI_INIT:
-               e->command = "dahdi set swgain";
+               e->command = "dahdi set swgain {rx|tx}";
                e->usage =
                        "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
-                       "       Sets the software gain on a a given channel, overriding the\n"
-                       "   value provided at module loadtime, whether the channel is in\n"
-                       "   use or not.  Changes take effect immediately.\n"
+                       "   Sets the software gain on a given channel and overrides the\n"
+                       "   value provided at module loadtime.  Changes take effect\n"
+                       "   immediately whether the channel is in use or not.\n"
+                       "\n"
                        "   <rx|tx> which direction do you want to change (relative to our module)\n"
                        "   <chan num> is the channel number relative to the device\n"
                        "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
@@ -15242,8 +15522,14 @@ static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                        return CLI_FAILURE;
                }
 
-               ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
+               ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
                        tx ? "tx" : "rx", gain, channel);
+
+               if (tx) {
+                       tmp->txgain = gain;
+               } else {
+                       tmp->rxgain = gain;
+               }
                break;
        }
        ast_mutex_unlock(&iflock);
@@ -15317,7 +15603,8 @@ static struct ast_cli_entry dahdi_cli[] = {
        AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
        AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
        AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
-       AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
+       AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
+       AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
        AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
        AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
        AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
@@ -15432,7 +15719,7 @@ static int action_transfer(struct mansession *s, const struct message *m)
                astman_send_error(s, m, "No such channel");
                return 0;
        }
-       if (!analog_lib_handles(p->sig, 0, 0)) {
+       if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
                astman_send_error(s, m, "Channel signaling is not analog");
                return 0;
        }
@@ -15455,7 +15742,7 @@ static int action_transferhangup(struct mansession *s, const struct message *m)
                astman_send_error(s, m, "No such channel");
                return 0;
        }
-       if (!analog_lib_handles(p->sig, 0, 0)) {
+       if (!dahdi_analog_lib_handles(p->sig, 0, 0)) {
                astman_send_error(s, m, "Channel signaling is not analog");
                return 0;
        }
@@ -16216,8 +16503,10 @@ static int __unload_module(void)
 
 #ifdef HAVE_PRI
        for (i = 0; i < NUM_SPANS; i++) {
-               if (pris[i].pri.master != AST_PTHREADT_NULL)
+               if (pris[i].pri.master != AST_PTHREADT_NULL) {
                        pthread_cancel(pris[i].pri.master);
+                       pthread_kill(pris[i].pri.master, SIGURG);
+               }
        }
        ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
        ast_unregister_application(dahdi_send_keypad_facility_app);
@@ -16227,9 +16516,11 @@ static int __unload_module(void)
 #endif
 #if defined(HAVE_SS7)
        for (i = 0; i < NUM_SPANS; i++) {
-               if (linksets[i].ss7.master != AST_PTHREADT_NULL)
+               if (linksets[i].ss7.master != AST_PTHREADT_NULL) {
                        pthread_cancel(linksets[i].ss7.master);
+                       pthread_kill(linksets[i].ss7.master, SIGURG);
                }
+       }
        ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
 #endif /* defined(HAVE_SS7) */
 #if defined(HAVE_OPENR2)
@@ -16273,8 +16564,9 @@ static int __unload_module(void)
 
 #if defined(HAVE_PRI)
        for (i = 0; i < NUM_SPANS; i++) {
-               if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL))
+               if (pris[i].pri.master && (pris[i].pri.master != AST_PTHREADT_NULL)) {
                        pthread_join(pris[i].pri.master, NULL);
+               }
                for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) {
                        dahdi_close_pri_fd(&(pris[i]), j);
                }
@@ -16289,8 +16581,9 @@ static int __unload_module(void)
 
 #if defined(HAVE_SS7)
        for (i = 0; i < NUM_SPANS; i++) {
-               if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL))
+               if (linksets[i].ss7.master && (linksets[i].ss7.master != AST_PTHREADT_NULL)) {
                        pthread_join(linksets[i].ss7.master, NULL);
+               }
                for (j = 0; j < SIG_SS7_NUM_DCHANS; j++) {
                        dahdi_close_ss7_fd(&(linksets[i]), j);
                }
@@ -16344,7 +16637,7 @@ static char *parse_spanchan(char *chanstr, char **subdir)
        return p;
 }
 
-static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno, int *found_pseudo)
+static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
 {
        char *c, *chan;
        char *subdir;
@@ -16367,8 +16660,6 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r
                        finish = start;
                } else if (!strcasecmp(chan, "pseudo")) {
                        finish = start = CHAN_PSEUDO;
-                       if (found_pseudo)
-                               *found_pseudo = 1;
                } else {
                        ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
                        return -1;
@@ -16398,6 +16689,12 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r
                                        }
                                }
                        }
+                       if (conf->wanted_channels_start &&
+                               (real_channel < conf->wanted_channels_start ||
+                                real_channel > conf->wanted_channels_end)
+                          ) {
+                               continue;
+                       }
                        tmp = mkintf(real_channel, conf, reload);
 
                        if (tmp) {
@@ -16407,6 +16704,9 @@ static int build_channels(struct dahdi_chan_conf *conf, const char *value, int r
                                                (reload == 1) ? "reconfigure" : "register", value);
                                return -1;
                        }
+                       if (real_channel == CHAN_PSEUDO) {
+                               has_pseudo = 1;
+                       }
                }
        }
 
@@ -16562,13 +16862,13 @@ static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_patte
 
        for (; ;) {
                /* Scans the string for the next value in the pattern. If none, it checks to see if any have been entered so far. */
-               if(!sscanf(v->value, "%30d", &norval) && count_pattern == 0) { 
+               if(!sscanf(v->value, "%30d", &norval) && count_pattern == 0) {
                        ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
                        break;
                }
 
-               busy_cadence->pattern[count_pattern] = norval; 
-               
+               busy_cadence->pattern[count_pattern] = norval;
+
                count_pattern++;
                if (count_pattern == 4) {
                        break;
@@ -16582,18 +16882,17 @@ static void parse_busy_pattern(struct ast_variable *v, struct ast_dsp_busy_patte
        }
        busy_cadence->length = count_pattern;
 
-       if (count_pattern % 2 != 0) { 
+       if (count_pattern % 2 != 0) {
                /* The pattern length must be divisible by two */
                ast_log(LOG_ERROR, "busypattern= expects either busypattern=tonelength,quietlength or busypattern=t1length, q1length, t2length, q2length at line %d.\n", v->lineno);
        }
-       
+
 }
 
 static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
 {
        struct dahdi_pvt *tmp;
        int y;
-       int found_pseudo = 0;
        struct ast_variable *dahdichan = NULL;
 
        for (; v; v = v->next) {
@@ -16606,7 +16905,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                                ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
                                continue;
                        }
-                       if (build_channels(confp, v->value, reload, v->lineno, &found_pseudo)) {
+                       if (build_channels(confp, v->value, reload, v->lineno)) {
                                if (confp->ignore_failed_channels) {
                                        ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
                                        continue;
@@ -16827,6 +17126,24 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                        if (ast_true(v->value)) {
                                confp->chan.mwimonitor_fsk = 1;
                        }
+               } else if (!strcasecmp(v->name, "hwrxgain")) {
+                       confp->chan.hwrxgain_enabled = 0;
+                       if (strcasecmp(v->value, "disabled")) {
+                               if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
+                                       confp->chan.hwrxgain_enabled = 1;
+                               } else {
+                                       ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
+                               }
+                       }
+               } else if (!strcasecmp(v->name, "hwtxgain")) {
+                       confp->chan.hwtxgain_enabled = 0;
+                       if (strcasecmp(v->value, "disabled")) {
+                               if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
+                                       confp->chan.hwtxgain_enabled = 1;
+                               } else {
+                                       ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
+                               }
+                       }
                } else if (!strcasecmp(v->name, "cid_rxgain")) {
                        if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
                                ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
@@ -17244,7 +17561,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
                        } else if (!strcasecmp(v->name, "service_message_support")) {
                                /* assuming switchtype for this channel group has been configured already */
-                               if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS 
+                               if ((confp->pri.pri.switchtype == PRI_SWITCH_ATT4ESS
                                        || confp->pri.pri.switchtype == PRI_SWITCH_LUCENT5E
                                        || confp->pri.pri.switchtype == PRI_SWITCH_NI2) && ast_true(v->value)) {
                                        confp->pri.pri.enable_service_message_support = 1;
@@ -17739,8 +18056,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 
        if (dahdichan) {
                /* Process the deferred dahdichan value. */
-               if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno,
-                       &found_pseudo)) {
+               if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
                        if (confp->ignore_failed_channels) {
                                ast_log(LOG_WARNING,
                                        "Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
@@ -17755,7 +18071,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
        for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
                if (!tmp->destroy && tmp->span != y) {
                        tmp->manages_span_alarms = 1;
-                       y = tmp->span; 
+                       y = tmp->span;
                } else {
                        tmp->manages_span_alarms = 0;
                }
@@ -17763,7 +18079,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 
        /*< \todo why check for the pseudo in the per-channel section.
         * Any actual use for manual setup of the pseudo channel? */
-       if (!found_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
+       if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
                /* use the default configuration for a channel, so
                   that any settings from real configured channels
                   don't "leak" into the pseudo channel config
@@ -17777,6 +18093,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                }
                if (tmp) {
                        ast_verb(3, "Automatically generated pseudo channel\n");
+                       has_pseudo = 1;
                } else {
                        ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
                }
@@ -18056,7 +18373,8 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
        if (reload != 1) {
                int x;
                for (x = 0; x < NUM_SPANS; x++) {
-                       if (pris[x].pri.pvts[0]) {
+                       if (pris[x].pri.pvts[0] &&
+                                       pris[x].pri.master == AST_PTHREADT_NULL) {
                                prepare_pri(pris + x);
                                if (sig_pri_start_pri(&pris[x].pri)) {
                                        ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
@@ -18290,8 +18608,8 @@ static const struct ast_data_entry dahdi_data_providers[] = {
  * Module loading including tests for configuration or dependencies.
  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
+ * configuration file or other non-critical problem return
  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
  */
 static int load_module(void)
@@ -18306,7 +18624,7 @@ static int load_module(void)
                return AST_MODULE_LOAD_FAILURE;
        }
 
-       if (!(dahdi_tech.capabilities = ast_format_cap_alloc())) {
+       if (!(dahdi_tech.capabilities = ast_format_cap_alloc(0))) {
                return AST_MODULE_LOAD_FAILURE;
        }
        ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));