chan_vpb: Fix a gcc 7 out-of-bounds complaint
[asterisk/asterisk.git] / addons / chan_mobile.c
index 415ca61..8f04af7 100644 (file)
  * \ingroup channel_drivers
  */
 
+/*! \li \ref chan_mobile.c uses the configuration file \ref chan_mobile.conf
+ * \addtogroup configuration_file Configuration Files
+ */
+
+/*!
+ * \page chan_mobile.conf chan_mobile.conf
+ * \verbinclude chan_mobile.conf.sample
+ */
+
 /*** MODULEINFO
        <depend>bluetooth</depend>
        <defaultenabled>no</defaultenabled>
+       <support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <pthread.h>
 #include <signal.h>
 
@@ -63,15 +71,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/manager.h"
 #include "asterisk/io.h"
+#include "asterisk/smoother.h"
+#include "asterisk/format_cache.h"
 
-#define MBL_CONFIG "mobile.conf"
+#define MBL_CONFIG "chan_mobile.conf"
+#define MBL_CONFIG_OLD "mobile.conf"
 
 #define DEVICE_FRAME_SIZE 48
-#define DEVICE_FRAME_FORMAT AST_FORMAT_SLINEAR
+#define DEVICE_FRAME_FORMAT ast_format_slin
 #define CHANNEL_FRAME_SIZE 320
 
-static int prefformat = DEVICE_FRAME_FORMAT;
-
 static int discovery_interval = 60;                    /* The device discovery interval, default 60 seconds. */
 static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */
 static sdp_session_t *sdp_session;
@@ -135,7 +144,8 @@ struct mbl_pvt {
        int alignment_count;
        int ring_sched_id;
        struct ast_dsp *dsp;
-       struct sched_context *sched;
+       struct ast_sched_context *sched;
+       int hangupcause;
 
        /* flags */
        unsigned int outgoing:1;        /*!< outgoing call */
@@ -145,7 +155,7 @@ struct mbl_pvt {
        unsigned int needcallerid:1;    /*!< we need callerid */
        unsigned int needchup:1;        /*!< we need to send a chup */
        unsigned int needring:1;        /*!< we need to send a RING */
-       unsigned int answered:1;        /*!< we sent/recieved an answer */
+       unsigned int answered:1;        /*!< we sent/received an answer */
        unsigned int connected:1;       /*!< do we have an rfcomm connection to a device */
 
        AST_LIST_ENTRY(mbl_pvt) entry;
@@ -160,17 +170,23 @@ static int handle_response_clip(struct mbl_pvt *pvt, char *buf);
 static int handle_response_ring(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
+static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
+static int handle_response_busy(struct mbl_pvt *pvt);
+static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf);
+static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf);
 static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);
 
 /* CLI stuff */
 static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *handle_cli_mobile_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 
 static struct ast_cli_entry mbl_cli[] = {
        AST_CLI_DEFINE(handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices"),
        AST_CLI_DEFINE(handle_cli_mobile_search,       "Search for Bluetooth Cell / Mobile devices"),
        AST_CLI_DEFINE(handle_cli_mobile_rfcomm,       "Send commands to the rfcomm port for debugging"),
+       AST_CLI_DEFINE(handle_cli_mobile_cusd,         "Send CUSD commands to the mobile"),
 };
 
 /* App stuff */
@@ -191,23 +207,24 @@ static char *mblsendsms_desc =
 "  Message - text of the message\n";
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
-               const struct ast_channel *requestor);
-static struct ast_channel *mbl_request(const char *type, int format,
-               const struct ast_channel *requestor, void *data, int *cause);
-static int mbl_call(struct ast_channel *ast, char *dest, int timeout);
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
+static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static int mbl_call(struct ast_channel *ast, const char *dest, int timeout);
 static int mbl_hangup(struct ast_channel *ast);
 static int mbl_answer(struct ast_channel *ast);
 static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static struct ast_frame *mbl_read(struct ast_channel *ast);
 static int mbl_write(struct ast_channel *ast, struct ast_frame *frame);
 static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int mbl_devicestate(void *data);
+static int mbl_devicestate(const char *data);
 
 static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen);
 
 static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control);
 static int mbl_queue_hangup(struct mbl_pvt *pvt);
 static int mbl_ast_hangup(struct mbl_pvt *pvt);
+static int mbl_has_service(struct mbl_pvt *pvt);
 
 static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel);
 static int rfcomm_write(int rsock, char *buf);
@@ -267,6 +284,10 @@ static int headset_send_ring(const void *data);
 #define HFP_CIND_CALLSETUP_OUTGOING    2
 #define HFP_CIND_CALLSETUP_ALERTING    3
 
+/* service indicator values */
+#define HFP_CIND_SERVICE_NONE          0
+#define HFP_CIND_SERVICE_AVAILABLE     1
+
 /*!
  * \brief This struct holds HFP features that we support.
  */
@@ -322,6 +343,7 @@ struct hfp_pvt {
        struct hfp_cind cind_map;       /*!< the cind name to index mapping for this AG */
        int rsock;                      /*!< our rfcomm socket */
        int rport;                      /*!< our rfcomm port */
+       int sent_alerting;              /*!< have we sent alerting? */
 };
 
 
@@ -346,6 +368,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
 static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf);
 static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf);
 static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf);
+static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf);
 
 static int hfp_brsf2int(struct hfp_hf *hf);
 static struct hfp_ag *hfp_int2brsf(int brsf, struct hfp_ag *ag);
@@ -369,6 +392,7 @@ static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message);
 static int hfp_send_chup(struct hfp_pvt *hfp);
 static int hfp_send_atd(struct hfp_pvt *hfp, const char *number);
 static int hfp_send_ata(struct hfp_pvt *hfp);
+static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code);
 
 /*
  * bluetooth headset profile helpers
@@ -413,6 +437,11 @@ typedef enum {
        AT_CNMI,
        AT_CMER,
        AT_CIND_TEST,
+       AT_CUSD,
+       AT_BUSY,
+       AT_NO_DIALTONE,
+       AT_NO_CARRIER,
+       AT_ECAM,
 } at_message_t;
 
 static int at_match_prefix(char *buf, char *prefix);
@@ -438,10 +467,9 @@ static struct msg_queue_entry *msg_queue_head(struct mbl_pvt *pvt);
  * channel stuff
  */
 
-static const struct ast_channel_tech mbl_tech = {
+static struct ast_channel_tech mbl_tech = {
        .type = "Mobile",
        .description = "Bluetooth Mobile Device Channel Driver",
-       .capabilities = AST_FORMAT_SLINEAR,
        .requester = mbl_request,
        .call = mbl_call,
        .hangup = mbl_hangup,
@@ -461,7 +489,7 @@ static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, st
        char bdaddr[18];
        char group[6];
 
-#define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-5.5s %-3.3s\n"
+#define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\n"
 
        switch (cmd) {
        case CLI_INIT:
@@ -489,7 +517,7 @@ static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, st
                                group,
                                pvt->adapter->id,
                                pvt->connected ? "Yes" : "No",
-                               (!pvt->connected) ? "None" : (pvt->owner) ? "Busy" : (pvt->outgoing_sms || pvt->incoming_sms) ? "SMS" : "Free",
+                               (!pvt->connected) ? "None" : (pvt->owner) ? "Busy" : (pvt->outgoing_sms || pvt->incoming_sms) ? "SMS" : (mbl_has_service(pvt)) ? "Free" : "No Service",
                                (pvt->has_sms) ? "Yes" : "No"
                       );
                ast_mutex_unlock(&pvt->lock);
@@ -545,7 +573,7 @@ static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct a
        max_rsp = 255;
        flags = IREQ_CACHE_FLUSH;
 
-       ii = alloca(max_rsp * sizeof(inquiry_info));
+       ii = ast_alloca(max_rsp * sizeof(inquiry_info));
        num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
        if (num_rsp > 0) {
                ast_cli(a->fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
@@ -619,6 +647,56 @@ e_return:
        return CLI_SUCCESS;
 }
 
+static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       char buf[128];
+       struct mbl_pvt *pvt = NULL;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "mobile cusd";
+               e->usage =
+                       "Usage: mobile cusd <device ID> <command>\n"
+                       "       Send cusd <command> to the rfcomm port on the device\n"
+                       "       with the specified <device ID>.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       if (a->argc != 4)
+               return CLI_SHOWUSAGE;
+
+       AST_RWLIST_RDLOCK(&devices);
+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
+               if (!strcmp(pvt->id, a->argv[2]))
+                       break;
+       }
+       AST_RWLIST_UNLOCK(&devices);
+
+       if (!pvt) {
+               ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
+               goto e_return;
+       }
+
+       ast_mutex_lock(&pvt->lock);
+       if (!pvt->connected) {
+               ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
+               goto e_unlock_pvt;
+       }
+
+       snprintf(buf, sizeof(buf), "%s", a->argv[3]);
+       if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) {
+               ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id);
+               goto e_unlock_pvt;
+       }
+
+e_unlock_pvt:
+       ast_mutex_unlock(&pvt->lock);
+e_return:
+       return CLI_SUCCESS;
+}
+
 /*
 
        Dialplan applications implementation
@@ -758,9 +836,8 @@ e_return:
 */
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
-               const struct ast_channel *requestor)
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 {
-
        struct ast_channel *chn;
 
        pvt->answered = 0;
@@ -775,29 +852,30 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num
        ast_dsp_digitreset(pvt->dsp);
 
        chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context,
-                       requestor ? requestor->linkedid : "", 0,
+                       assignedids, requestor, 0,
                        "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
        if (!chn) {
                goto e_return;
        }
 
-       chn->tech = &mbl_tech;
-       chn->nativeformats = prefformat;
-       chn->rawreadformat = prefformat;
-       chn->rawwriteformat = prefformat;
-       chn->writeformat = prefformat;
-       chn->readformat = prefformat;
-       chn->tech_pvt = pvt;
+       ast_channel_tech_set(chn, &mbl_tech);
+       ast_channel_nativeformats_set(chn, mbl_tech.capabilities);
+       ast_channel_set_rawreadformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_set_rawwriteformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_set_writeformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_set_readformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_tech_pvt_set(chn, pvt);
 
        if (state == AST_STATE_RING)
-               chn->rings = 1;
+               ast_channel_rings_set(chn, 1);
 
-       ast_string_field_set(chn, language, "en");
+       ast_channel_language_set(chn, "en");
        pvt->owner = chn;
 
        if (pvt->sco_socket != -1) {
                ast_channel_set_fd(chn, 0, pvt->sco_socket);
        }
+       ast_channel_unlock(chn);
 
        return chn;
 
@@ -805,15 +883,15 @@ e_return:
        return NULL;
 }
 
-static struct ast_channel *mbl_request(const char *type, int format,
-               const struct ast_channel *requestor, void *data, int *cause)
+static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 {
 
        struct ast_channel *chn = NULL;
        struct mbl_pvt *pvt;
        char *dest_dev = NULL;
        char *dest_num = NULL;
-       int oldformat, group = -1;
+       int group = -1;
 
        if (!data) {
                ast_log(LOG_WARNING, "Channel requested with no data\n");
@@ -821,15 +899,14 @@ static struct ast_channel *mbl_request(const char *type, int format,
                return NULL;
        }
 
-       oldformat = format;
-       format &= (AST_FORMAT_SLINEAR);
-       if (!format) {
-               ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%d'\n", oldformat);
+       if (ast_format_cap_iscompatible_format(cap, DEVICE_FRAME_FORMAT) == AST_FORMAT_CMP_NOT_EQUAL) {
+               struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
                *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
                return NULL;
        }
 
-       dest_dev = ast_strdupa((char *)data);
+       dest_dev = ast_strdupa(data);
 
        dest_num = strchr(dest_dev, '/');
        if (dest_num)
@@ -843,6 +920,10 @@ static struct ast_channel *mbl_request(const char *type, int format,
        AST_RWLIST_RDLOCK(&devices);
        AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
                if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) {
+                       if (!mbl_has_service(pvt)) {
+                               continue;
+                       }
+
                        break;
                } else if (!strcmp(pvt->id, dest_dev)) {
                        break;
@@ -862,7 +943,7 @@ static struct ast_channel *mbl_request(const char *type, int format,
        }
 
        ast_mutex_lock(&pvt->lock);
-       chn = mbl_new(AST_STATE_DOWN, pvt, NULL, requestor);
+       chn = mbl_new(AST_STATE_DOWN, pvt, NULL, assignedids, requestor);
        ast_mutex_unlock(&pvt->lock);
        if (!chn) {
                ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
@@ -874,16 +955,15 @@ static struct ast_channel *mbl_request(const char *type, int format,
 
 }
 
-static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
+static int mbl_call(struct ast_channel *ast, const char *dest, int timeout)
 {
-
        struct mbl_pvt *pvt;
-       char *dest_dev = NULL;
+       char *dest_dev;
        char *dest_num = NULL;
 
-       dest_dev = ast_strdupa((char *)dest);
+       dest_dev = ast_strdupa(dest);
 
-       pvt = ast->tech_pvt;
+       pvt = ast_channel_tech_pvt(ast);
 
        if (pvt->type == MBL_TYPE_PHONE) {
                dest_num = strchr(dest_dev, '/');
@@ -894,12 +974,12 @@ static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
                *dest_num++ = 0x00;
        }
 
-       if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
-               ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast->name);
+       if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
+               ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
                return -1;
        }
 
-       ast_debug(1, "Calling %s on %s\n", dest, ast->name);
+       ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
 
        ast_mutex_lock(&pvt->lock);
        if (pvt->type == MBL_TYPE_PHONE) {
@@ -908,6 +988,7 @@ static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
                        ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
                        return -1;
                }
+               pvt->hangupcause = 0;
                pvt->needchup = 1;
                msg_queue_push(pvt, AT_OK, AT_D);
        } else {
@@ -937,11 +1018,11 @@ static int mbl_hangup(struct ast_channel *ast)
 
        struct mbl_pvt *pvt;
 
-       if (!ast->tech_pvt) {
+       if (!ast_channel_tech_pvt(ast)) {
                ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
                return 0;
        }
-       pvt = ast->tech_pvt;
+       pvt = ast_channel_tech_pvt(ast);
 
        ast_debug(1, "[%s] hanging up device\n", pvt->id);
 
@@ -960,7 +1041,7 @@ static int mbl_hangup(struct ast_channel *ast)
        pvt->incoming = 0;
        pvt->needring = 0;
        pvt->owner = NULL;
-       ast->tech_pvt = NULL;
+       ast_channel_tech_pvt_set(ast, NULL);
 
        ast_mutex_unlock(&pvt->lock);
 
@@ -975,7 +1056,7 @@ static int mbl_answer(struct ast_channel *ast)
 
        struct mbl_pvt *pvt;
 
-       pvt = ast->tech_pvt;
+       pvt = ast_channel_tech_pvt(ast);
 
        if (pvt->type == MBL_TYPE_HEADSET)
                return 0;
@@ -994,7 +1075,7 @@ static int mbl_answer(struct ast_channel *ast)
 
 static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
-       struct mbl_pvt *pvt = ast->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
 
        if (pvt->type == MBL_TYPE_HEADSET)
                return 0;
@@ -1016,7 +1097,7 @@ static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int durat
 static struct ast_frame *mbl_read(struct ast_channel *ast)
 {
 
-       struct mbl_pvt *pvt = ast->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
        struct ast_frame *fr = &ast_null_frame;
        int r;
 
@@ -1032,7 +1113,7 @@ static struct ast_frame *mbl_read(struct ast_channel *ast)
 
        memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
        pvt->fr.frametype = AST_FRAME_VOICE;
-       pvt->fr.subclass = DEVICE_FRAME_FORMAT;
+       pvt->fr.subclass.format = DEVICE_FRAME_FORMAT;
        pvt->fr.src = "Mobile";
        pvt->fr.offset = AST_FRIENDLY_OFFSET;
        pvt->fr.mallocd = 0;
@@ -1070,7 +1151,7 @@ e_return:
 static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
 {
 
-       struct mbl_pvt *pvt = ast->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
        struct ast_frame *f;
 
        ast_debug(3, "*** mbl_write\n");
@@ -1087,7 +1168,6 @@ static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
 
        while ((f = ast_smoother_read(pvt->smoother))) {
                sco_write(pvt->sco_socket, f->data.ptr, f->datalen);
-               ast_frfree(f);
        }
 
        ast_mutex_unlock(&pvt->lock);
@@ -1099,10 +1179,10 @@ static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
 static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
 
-       struct mbl_pvt *pvt = oldchan->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(newchan);
 
        if (!pvt) {
-               ast_debug(1, "fixup failed, no pvt on oldchan\n");
+               ast_debug(1, "fixup failed, no pvt on newchan\n");
                return -1;
        }
 
@@ -1115,7 +1195,7 @@ static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 
 }
 
-static int mbl_devicestate(void *data)
+static int mbl_devicestate(const char *data)
 {
 
        char *device;
@@ -1142,6 +1222,9 @@ static int mbl_devicestate(void *data)
                        res = AST_DEVICE_INUSE;
                else
                        res = AST_DEVICE_NOT_INUSE;
+
+               if (!mbl_has_service(pvt))
+                       res = AST_DEVICE_UNAVAILABLE;
        }
        ast_mutex_unlock(&pvt->lock);
 
@@ -1173,7 +1256,7 @@ static int mbl_devicestate(void *data)
        If the end result > 100, and it usually is if we have the problem, set a flag and compensate by shifting the bytes
        for each subsequent frame during the call.
 
-       If the result is <= 100 then clear the flag so we dont come back in here...
+       If the result is <= 100 then clear the flag so we don't come back in here...
 
        This seems to work OK....
 
@@ -1239,6 +1322,9 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
                        if (ast_channel_trylock(pvt->owner)) {
                                DEADLOCK_AVOIDANCE(&pvt->lock);
                        } else {
+                               if (pvt->hangupcause != 0) {
+                                       ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause);
+                               }
                                ast_queue_hangup(pvt->owner);
                                ast_channel_unlock(pvt->owner);
                                break;
@@ -1251,21 +1337,32 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
 
 static int mbl_ast_hangup(struct mbl_pvt *pvt)
 {
-       int res = 0;
-       for (;;) {
-               if (pvt->owner) {
-                       if (ast_channel_trylock(pvt->owner)) {
-                               DEADLOCK_AVOIDANCE(&pvt->lock);
-                       } else {
-                               res = ast_hangup(pvt->owner);
-                               /* no need to unlock, ast_hangup() frees the
-                                * channel */
-                               break;
-                       }
-               } else
-                       break;
-       }
-       return res;
+       ast_hangup(pvt->owner);
+       return 0;
+}
+
+/*!
+ * \brief Check if a mobile device has service.
+ * \param pvt a mbl_pvt struct
+ * \retval 1 this device has service
+ * \retval 0 no service
+ *
+ * \note This function will always indicate that service is available if the
+ * given device does not support service indication.
+ */
+static int mbl_has_service(struct mbl_pvt *pvt)
+{
+
+       if (pvt->type != MBL_TYPE_PHONE)
+               return 1;
+
+       if (!pvt->hfp->cind_map.service)
+               return 1;
+
+       if (pvt->hfp->cind_state[pvt->hfp->cind_map.service] == HFP_CIND_SERVICE_AVAILABLE)
+               return 1;
+
+       return 0;
 }
 
 /*
@@ -1288,7 +1385,7 @@ static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel)
        memset(&addr, 0, sizeof(addr));
        addr.rc_family = AF_BLUETOOTH;
        bacpy(&addr.rc_bdaddr, &src);
-       addr.rc_channel = (uint8_t) 1;
+       addr.rc_channel = (uint8_t) 0;
        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                ast_debug(1, "bind() failed (%d).\n", errno);
                close(s);
@@ -1445,8 +1542,8 @@ static int rfcomm_read_and_append_char(int rsock, char **buf, size_t count, size
 }
 
 /*!
- * \brief Read until '\r\n'.
- * This function consumes the '\r\n' but does not add it to buf.
+ * \brief Read until \verbatim '\r\n'. \endverbatim
+ * This function consumes the \verbatim'\r\n'\endverbatim but does not add it to buf.
  */
 static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1473,7 +1570,7 @@ static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *i
 
 /*!
  * \brief Read the remainder of an AT SMS prompt.
- * \note the entire parsed string is '\r\n> '
+ * \note the entire parsed string is \verbatim '\r\n> ' \endverbatim
  *
  * By the time this function is executed, only a ' ' is left to read.
  */
@@ -1491,8 +1588,123 @@ e_return:
 }
 
 /*!
+ * \brief Read until a \verbatim \r\nOK\r\n \endverbatim message.
+ */
+static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
+{
+       int res;
+       char c;
+
+       /* here, we read until finding a \r\n, then we read one character at a
+        * time looking for the string '\r\nOK\r\n'.  If we only find a partial
+        * match, we place that in the buffer and try again. */
+
+       for (;;) {
+               if ((res = rfcomm_read_until_crlf(rsock, buf, count, in_count)) != 1) {
+                       break;
+               }
+
+               rfcomm_append_buf(buf, count, in_count, '\r');
+               rfcomm_append_buf(buf, count, in_count, '\n');
+
+               if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
+                       if (res != -2) {
+                               break;
+                       }
+
+                       rfcomm_append_buf(buf, count, in_count, c);
+                       continue;
+               }
+
+               if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
+                       if (res != -2) {
+                               break;
+                       }
+
+                       rfcomm_append_buf(buf, count, in_count, '\r');
+                       rfcomm_append_buf(buf, count, in_count, c);
+                       continue;
+               }
+               if ((res = rfcomm_read_and_expect_char(rsock, &c, 'O')) != 1) {
+                       if (res != -2) {
+                               break;
+                       }
+
+                       rfcomm_append_buf(buf, count, in_count, '\r');
+                       rfcomm_append_buf(buf, count, in_count, '\n');
+                       rfcomm_append_buf(buf, count, in_count, c);
+                       continue;
+               }
+
+               if ((res = rfcomm_read_and_expect_char(rsock, &c, 'K')) != 1) {
+                       if (res != -2) {
+                               break;
+                       }
+
+                       rfcomm_append_buf(buf, count, in_count, '\r');
+                       rfcomm_append_buf(buf, count, in_count, '\n');
+                       rfcomm_append_buf(buf, count, in_count, 'O');
+                       rfcomm_append_buf(buf, count, in_count, c);
+                       continue;
+               }
+
+               if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
+                       if (res != -2) {
+                               break;
+                       }
+
+                       rfcomm_append_buf(buf, count, in_count, '\r');
+                       rfcomm_append_buf(buf, count, in_count, '\n');
+                       rfcomm_append_buf(buf, count, in_count, 'O');
+                       rfcomm_append_buf(buf, count, in_count, 'K');
+                       rfcomm_append_buf(buf, count, in_count, c);
+                       continue;
+               }
+
+               if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
+                       if (res != -2) {
+                               break;
+                       }
+
+                       rfcomm_append_buf(buf, count, in_count, '\r');
+                       rfcomm_append_buf(buf, count, in_count, '\n');
+                       rfcomm_append_buf(buf, count, in_count, 'O');
+                       rfcomm_append_buf(buf, count, in_count, 'K');
+                       rfcomm_append_buf(buf, count, in_count, '\r');
+                       rfcomm_append_buf(buf, count, in_count, c);
+                       continue;
+               }
+
+               /* we have successfully parsed a '\r\nOK\r\n' string */
+               return 1;
+       }
+
+       return res;
+}
+
+
+/*!
+ * \brief Read the remainder of a +CMGR message.
+ * \note the entire parsed string is \verbatim '+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n' \endverbatim
+ */
+static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
+{
+       int res;
+
+       /* append the \r\n that was stripped by the calling function */
+       rfcomm_append_buf(buf, count, in_count, '\r');
+       rfcomm_append_buf(buf, count, in_count, '\n');
+
+       if ((res = rfcomm_read_until_ok(rsock, buf, count, in_count)) != 1) {
+               ast_log(LOG_ERROR, "error reading +CMGR message on rfcomm socket\n");
+       }
+
+       return res;
+}
+
+/*!
  * \brief Read and AT result code.
- * \note the entire parsed string is '\r\n<result code>\r\n'
+ * \note the entire parsed string is \verbatim '\r\n<result code>\r\n' \endverbatim
  */
 static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1515,23 +1727,22 @@ static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_co
        if (res != 1)
                return res;
 
-       /* check for CMGR, which contains an embedded \r\n */
+       /* check for CMGR, which contains an embedded \r\n pairs terminated by
+        * an \r\nOK\r\n message */
        if (*in_count >= 5 && !strncmp(*buf - *in_count, "+CMGR", 5)) {
-               rfcomm_append_buf(buf, count, in_count, '\r');
-               rfcomm_append_buf(buf, count, in_count, '\n');
-               return rfcomm_read_until_crlf(rsock, buf, count, in_count);
+               return rfcomm_read_cmgr(rsock, buf, count, in_count);
        }
 
        return 1;
 
 e_return:
-       ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket");
+       ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket\n");
        return res;
 }
 
 /*!
  * \brief Read the remainder of an AT command.
- * \note the entire parsed string is '<at command>\r'
+ * \note the entire parsed string is \verbatim '<at command>\r' \endverbatim
  */
 static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1565,8 +1776,8 @@ static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_c
  * \endverbatim
  *
  * These formats correspond to AT result codes, AT commands, and the AT SMS
- * prompt respectively.  When messages are read the leading and trailing '\r'
- * and '\n' characters are discarded.  If the given buffer is not large enough
+ * prompt respectively.  When messages are read the leading and trailing \verbatim '\r' \endverbatim
+ * and \verbatim '\n' \endverbatim characters are discarded.  If the given buffer is not large enough
  * to hold the response, what does not fit in the buffer will be dropped.
  *
  * \note The rfcomm connection to the device is asynchronous, so there is no
@@ -1826,6 +2037,16 @@ static at_message_t at_read_full(int rsock, char *buf, size_t count)
                return AT_VGM;
        } else if (at_match_prefix(buf, "AT+VGS=")) {
                return AT_VGS;
+       } else if (at_match_prefix(buf, "+CUSD:")) {
+               return AT_CUSD;
+       } else if (at_match_prefix(buf, "BUSY")) {
+               return AT_BUSY;
+       } else if (at_match_prefix(buf, "NO DIALTONE")) {
+               return AT_NO_DIALTONE;
+       } else if (at_match_prefix(buf, "NO CARRIER")) {
+               return AT_NO_CARRIER;
+       } else if (at_match_prefix(buf, "*ECAV:")) {
+               return AT_ECAM;
        } else {
                return AT_UNKNOWN;
        }
@@ -1870,6 +2091,12 @@ static inline const char *at_msg2str(at_message_t msg)
                return "SMS PROMPT";
        case AT_CMS_ERROR:
                return "+CMS ERROR";
+       case AT_BUSY:
+               return "BUSY";
+       case AT_NO_DIALTONE:
+               return "NO DIALTONE";
+       case AT_NO_CARRIER:
+               return "NO CARRIER";
        /* at commands */
        case AT_A:
                return "ATA";
@@ -1895,6 +2122,10 @@ static inline const char *at_msg2str(at_message_t msg)
                return "AT+CMER";
        case AT_CIND_TEST:
                return "AT+CIND=?";
+       case AT_CUSD:
+               return "AT+CUSD";
+       case AT_ECAM:
+               return "AT*ECAM";
        }
 }
 
@@ -1903,6 +2134,40 @@ static inline const char *at_msg2str(at_message_t msg)
  * bluetooth handsfree profile helpers
  */
 
+ /*!
+ * \brief Parse a ECAV event.
+ * \param hfp an hfp_pvt struct
+ * \param buf the buffer to parse (null terminated)
+ * \return -1 on error (parse error) or a ECAM value on success
+ *
+ * Example string: *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>]
+ * [,exitcause][,<number>,<type>]
+ *
+ * Example indicating busy: *ECAV: 1,7,1
+ */
+static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
+{
+       int ccid = 0;
+       int ccstatus = 0;
+       int calltype = 0;
+
+       if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
+               ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
+               return -1;
+       }
+
+       return ccstatus;
+}
+
+/*!
+ * \brief Enable Sony Erricson extensions / indications.
+ * \param hfp an hfp_pvt struct
+ */
+static int hfp_send_ecam(struct hfp_pvt *hfp)
+{
+       return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
+}
+
 /*!
  * \brief Parse a CIEV event.
  * \param hfp an hfp_pvt struct
@@ -1922,7 +2187,7 @@ static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
                return HFP_CIND_NONE;
        }
 
-       if (i >= sizeof(hfp->cind_state)) {
+       if (i >= ARRAY_LEN(hfp->cind_state)) {
                ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
                return HFP_CIND_NONE;
        }
@@ -1935,10 +2200,9 @@ static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
  * \brief Parse a CLIP event.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * @note buf will be modified when the CID string is parsed
+ * \note buf will be modified when the CID string is parsed
  * \return NULL on error (parse error) or a pointer to the caller id
- * inforamtion in buf
- * success
+ * information in buf
  */
 static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
 {
@@ -1982,7 +2246,7 @@ static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
  * \brief Parse a CMTI notification.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * @note buf will be modified when the CMTI message is parsed
+ * \note buf will be modified when the CMTI message is parsed
  * \return -1 on error (parse error) or the index of the new sms message
  */
 static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
@@ -2007,7 +2271,7 @@ static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
  * \param from_number a pointer to a char pointer which will store the from
  * number
  * \param text a pointer to a char pointer which will store the message text
- * @note buf will be modified when the CMGR message is parsed
+ * \note buf will be modified when the CMGR message is parsed
  * \retval -1 parse error
  * \retval 0 success
  */
@@ -2022,7 +2286,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
         */
        state = 0;
        s = strlen(buf);
-       for (i = 0; i < s && s != 6; i++) {
+       for (i = 0; i < s && state != 6; i++) {
                switch (state) {
                case 0: /* search for start of the number section (,) */
                        if (buf[i] == ',') {
@@ -2033,6 +2297,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
                        if (buf[i] == '"') {
                                state++;
                        }
+                       break;
                case 2: /* mark the start of the number */
                        if (from_number) {
                                *from_number = &buf[i];
@@ -2067,6 +2332,61 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
 }
 
 /*!
+ * \brief Parse a CUSD answer.
+ * \param hfp an hfp_pvt struct
+ * \param buf the buffer to parse (null terminated)
+ * \note buf will be modified when the CUSD string is parsed
+ * \return NULL on error (parse error) or a pointer to the cusd message
+ * information in buf
+ */
+static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
+{
+       int i, message_start, message_end;
+       char *cusd;
+       size_t s;
+
+       /* parse cusd message in the following format:
+        * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#."
+        */
+       message_start = 0;
+       message_end = 0;
+       s = strlen(buf);
+
+       /* Find the start of the message (") */
+       for (i = 0; i < s; i++) {
+               if (buf[i] == '"') {
+                       message_start = i + 1;
+                       break;
+               }
+       }
+
+       if (message_start == 0 || message_start >= s) {
+               return NULL;
+       }
+
+       /* Find the end of the message (") */
+       for (i = s; i > 0; i--) {
+               if (buf[i] == '"') {
+                       message_end = i;
+                       break;
+               }
+       }
+
+       if (message_end == 0) {
+               return NULL;
+       }
+
+       if (message_start >= message_end) {
+               return NULL;
+       }
+
+       cusd = &buf[message_start];
+       buf[message_end] = '\0';
+
+       return cusd;
+}
+
+/*!
  * \brief Convert a hfp_hf struct to a BRSF int.
  * \param hf an hfp_hf brsf object
  * \return an integer representing the given brsf struct
@@ -2311,6 +2631,18 @@ static int hfp_send_ata(struct hfp_pvt *hfp)
 }
 
 /*!
+ * \brief Send CUSD.
+ * \param hfp an hfp_pvt struct
+ * \param code the CUSD code to send
+ */
+static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code)
+{
+       char cmd[128];
+       snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code);
+       return rfcomm_write(hfp->rsock, cmd);
+}
+
+/*!
  * \brief Parse BRSF data.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
@@ -2338,7 +2670,7 @@ static int hfp_parse_cind_indicator(struct hfp_pvt *hfp, int group, char *indica
        int value;
 
        /* store the current indicator */
-       if (group >= sizeof(hfp->cind_state)) {
+       if (group >= ARRAY_LEN(hfp->cind_state)) {
                ast_debug(1, "ignoring CIND state '%s' for group %d, we only support up to %d indicators\n", indicator, group, (int) sizeof(hfp->cind_state));
                return -1;
        }
@@ -2413,7 +2745,7 @@ static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
 {
        int i, state, group;
        size_t s;
-       char *indicator = NULL, *values;
+       char *indicator = NULL;
 
        hfp->nocallsetup = 1;
 
@@ -2452,7 +2784,6 @@ static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
                        }
                        break;
                case 5: /* mark the start of the value range */
-                       values = &buf[i];
                        state++;
                        break;
                case 6: /* find the end of the value range */
@@ -2570,7 +2901,7 @@ static int hsp_send_ring(int rsock)
 /*!
  * \brief Add an item to the back of the queue.
  * \param pvt a mbl_pvt structure
- * \param expect the msg we expect to recieve
+ * \param expect the msg we expect to receive
  * \param response_to the message that was sent to generate the expected
  * response
  */
@@ -2590,7 +2921,7 @@ static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t
 /*!
  * \brief Add an item to the back of the queue with data.
  * \param pvt a mbl_pvt structure
- * \param expect the msg we expect to recieve
+ * \param expect the msg we expect to receive
  * \param response_to the message that was sent to generate the expected
  * response
  * \param data data associated with this message, it will be freed when the
@@ -2713,7 +3044,6 @@ static int sdp_search(char *addr, int profile)
 
 static sdp_session_t *sdp_register(void)
 {
-
        uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
        uint8_t rfcomm_channel = 1;
        const char *service_name = "Asterisk PABX";
@@ -2724,7 +3054,6 @@ static sdp_session_t *sdp_register(void)
        sdp_list_t  *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
        sdp_data_t *channel = 0;
 
-       int err = 0;
        sdp_session_t *session = 0;
 
        sdp_record_t *record = sdp_record_alloc();
@@ -2760,8 +3089,12 @@ static sdp_session_t *sdp_register(void)
 
        if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
                ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
-       else
-               err = sdp_record_register(session, record, 0);
+       else {
+               if (sdp_record_register(session, record, 0) < 0) {
+                       ast_log(LOG_WARNING, "Failed to sdp_record_register error: %d\n", errno);
+                       return NULL;
+               }
+       }
 
        sdp_data_free(channel);
        sdp_list_free(rfcomm_list, 0);
@@ -2802,9 +3135,9 @@ static int handle_response_brsf(struct mbl_pvt *pvt, char *buf)
 
                msg_queue_free_and_pop(pvt);
        } else if (entry) {
-               ast_debug(1, "[%s] recieved unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+               ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
        } else {
-               ast_debug(1, "[%s] recieved unexpected AT message 'BRSF'\n", pvt->id);
+               ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
        }
 
        return 0;
@@ -2844,9 +3177,9 @@ static int handle_response_cind(struct mbl_pvt *pvt, char *buf)
                }
                msg_queue_free_and_pop(pvt);
        } else if (entry) {
-               ast_debug(1, "[%s] recieved unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+               ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
        } else {
-               ast_debug(1, "[%s] recieved unexpected AT message 'CIND'\n", pvt->id);
+               ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
        }
 
        return 0;
@@ -2869,7 +3202,7 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
        if ((entry = msg_queue_head(pvt)) && entry->expected == AT_OK) {
                switch (entry->response_to) {
 
-               /* initilization stuff */
+               /* initialization stuff */
                case AT_BRSF:
                        ast_debug(1, "[%s] BSRF sent successfully\n", pvt->id);
 
@@ -2892,6 +3225,7 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
 
                        ast_debug(2, "[%s] call: %d\n", pvt->id, pvt->hfp->cind_map.call);
                        ast_debug(2, "[%s] callsetup: %d\n", pvt->id, pvt->hfp->cind_map.callsetup);
+                       ast_debug(2, "[%s] service: %d\n", pvt->id, pvt->hfp->cind_map.service);
 
                        if (hfp_send_cind(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND)) {
                                ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
@@ -2940,6 +3274,14 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                        break;
                case AT_CLIP:
                        ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
+                       if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
+                               ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
+                               goto e_return;
+                       }
+
+                       break;
+               case AT_ECAM:
+                       ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
                        if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
                                ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
                                goto e_return;
@@ -2954,9 +3296,11 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                        ast_debug(1, "[%s] volume level synchronization successful\n", pvt->id);
 
                        /* set the SMS operating mode to text mode */
-                       if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
-                               ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
-                               goto e_return;
+                       if (pvt->has_sms) {
+                               if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
+                                       ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
+                                       goto e_return;
+                               }
                        }
                        break;
                case AT_CMGF:
@@ -2971,7 +3315,7 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                        ast_debug(1, "[%s] sms new message indication enabled\n", pvt->id);
                        pvt->has_sms = 1;
                        break;
-               /* end initilization stuff */
+               /* end initialization stuff */
 
                case AT_A:
                        ast_debug(1, "[%s] answer sent successfully\n", pvt->id);
@@ -2986,10 +3330,6 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                case AT_CHUP:
                        ast_debug(1, "[%s] successful hangup\n", pvt->id);
                        break;
-               case AT_CMGR:
-                       ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
-                       pvt->incoming_sms = 0;
-                       break;
                case AT_CMGS:
                        ast_debug(1, "[%s] successfully sent sms message\n", pvt->id);
                        pvt->outgoing_sms = 0;
@@ -2997,16 +3337,19 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                case AT_VTS:
                        ast_debug(1, "[%s] digit sent successfully\n", pvt->id);
                        break;
+               case AT_CUSD:
+                       ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id);
+                       break;
                case AT_UNKNOWN:
                default:
-                       ast_debug(1, "[%s] recieved OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
+                       ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
                        break;
                }
                msg_queue_free_and_pop(pvt);
        } else if (entry) {
-               ast_debug(1, "[%s] recieved AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+               ast_debug(1, "[%s] received AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
        } else {
-               ast_debug(1, "[%s] recieved unexpected AT message 'OK'\n", pvt->id);
+               ast_debug(1, "[%s] received unexpected AT message 'OK'\n", pvt->id);
        }
        return 0;
 
@@ -3033,7 +3376,7 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
                        || entry->expected == AT_SMS_PROMPT)) {
                switch (entry->response_to) {
 
-               /* initilization stuff */
+               /* initialization stuff */
                case AT_BRSF:
                        ast_debug(1, "[%s] error reading BSRF\n", pvt->id);
                        goto e_return;
@@ -3052,7 +3395,7 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
                case AT_VGS:
                        ast_debug(1, "[%s] volume level synchronization failed\n", pvt->id);
 
-                       /* this is not a fatal error, let's continue with initilization */
+                       /* this is not a fatal error, let's continue with initialization */
 
                        /* set the SMS operating mode to text mode */
                        if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
@@ -3061,14 +3404,31 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
                        }
                        break;
                case AT_CMGF:
+                       pvt->has_sms = 0;
                        ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
                        ast_debug(1, "[%s] no SMS support\n", pvt->id);
                        break;
                case AT_CNMI:
+                       pvt->has_sms = 0;
                        ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
                        ast_debug(1, "[%s] no SMS support\n", pvt->id);
                        break;
-               /* end initilization stuff */
+               case AT_ECAM:
+                       ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
+
+                       /* this is not a fatal error, let's continue with the initialization */
+
+                       if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
+                               ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
+                               goto e_return;
+                       }
+
+                       pvt->timeout = -1;
+                       pvt->hfp->initialized = 1;
+                       ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
+
+                       break;
+               /* end initialization stuff */
 
                case AT_A:
                        ast_debug(1, "[%s] answer failed\n", pvt->id);
@@ -3093,16 +3453,19 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
                case AT_VTS:
                        ast_debug(1, "[%s] error sending digit\n", pvt->id);
                        break;
+               case AT_CUSD:
+                       ast_verb(0, "[%s] error sending CUSD command\n", pvt->id);
+                       break;
                case AT_UNKNOWN:
                default:
-                       ast_debug(1, "[%s] recieved ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
+                       ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
                        break;
                }
                msg_queue_free_and_pop(pvt);
        } else if (entry) {
-               ast_debug(1, "[%s] recieved AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
+               ast_debug(1, "[%s] received AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
        } else {
-               ast_debug(1, "[%s] recieved unexpected AT message 'ERROR'\n", pvt->id);
+               ast_debug(1, "[%s] received unexpected AT message 'ERROR'\n", pvt->id);
        }
 
        return 0;
@@ -3160,6 +3523,9 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                case HFP_CIND_CALLSETUP_NONE:
                        if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
                                if (pvt->owner) {
+                                       if (pvt->hfp->sent_alerting == 1) {
+                                               handle_response_busy(pvt);
+                                       }
                                        if (mbl_queue_hangup(pvt)) {
                                                ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
                                                return -1;
@@ -3178,6 +3544,7 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                        break;
                case HFP_CIND_CALLSETUP_OUTGOING:
                        if (pvt->outgoing) {
+                               pvt->hfp->sent_alerting = 0;
                                ast_debug(1, "[%s] outgoing call\n", pvt->id);
                        } else {
                                ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
@@ -3188,6 +3555,7 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                        if (pvt->outgoing) {
                                ast_debug(1, "[%s] remote alerting\n", pvt->id);
                                mbl_queue_control(pvt, AST_CONTROL_RINGING);
+                               pvt->hfp->sent_alerting = 1;
                        }
                        break;
                }
@@ -3220,7 +3588,7 @@ static int handle_response_clip(struct mbl_pvt *pvt, char *buf)
                        ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);
                }
 
-               if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL))) {
+               if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL, NULL))) {
                        ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
                        hfp_send_chup(pvt->hfp);
                        msg_queue_push(pvt, AT_OK, AT_CHUP);
@@ -3301,20 +3669,21 @@ static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
        if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
                msg_queue_free_and_pop(pvt);
 
-               if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)
-                               || msg_queue_push(pvt, AT_OK, AT_CMGR)) {
-
+               if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)) {
                        ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
                        return -1;
                }
 
+               ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
+               pvt->incoming_sms = 0;
+
                /* XXX this channel probably does not need to be associated with this pvt */
-               if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL))) {
+               if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
                        ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
                        return -1;
                }
 
-               strcpy(chan->exten, "sms");
+               ast_channel_exten_set(chan, "sms");
                pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
                pbx_builtin_setvar_helper(chan, "SMSTXT", text);
 
@@ -3360,23 +3729,88 @@ static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf)
        return 0;
 }
 
+/*!
+ * \brief Handle CUSD messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
+{
+       char *cusd;
+
+       if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) {
+               ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf);
+               return 0;
+       }
+
+       ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd);
+
+       return 0;
+}
+
+/*!
+ * \brief Handle BUSY messages.
+ * \param pvt a mbl_pvt structure
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_busy(struct mbl_pvt *pvt)
+{
+       pvt->hangupcause = AST_CAUSE_USER_BUSY;
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_BUSY);
+       return 0;
+}
+
+/*!
+ * \brief Handle NO DIALTONE messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
+{
+       ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
+       return 0;
+}
+
+/*!
+ * \brief Handle NO CARRIER messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
+{
+       ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
+       return 0;
+}
+
 
 static void *do_monitor_phone(void *data)
 {
        struct mbl_pvt *pvt = (struct mbl_pvt *)data;
        struct hfp_pvt *hfp = pvt->hfp;
-       char buf[256];
+       char buf[350];
        int t;
        at_message_t at_msg;
        struct msg_queue_entry *entry;
 
-       /* Note: At one point the initilization procedure was neatly contained
-        * in the hfp_init() function, but that initilization method did not
-        * work with non standard devices.  As a result, the initilization
+       /* Note: At one point the initialization procedure was neatly contained
+        * in the hfp_init() function, but that initialization method did not
+        * work with non standard devices.  As a result, the initialization
         * procedure is not spread throughout the event handling loop.
         */
 
-       /* start initilization with the BRSF request */
+       /* start initialization with the BRSF request */
        ast_mutex_lock(&pvt->lock);
        pvt->timeout = 10000;
        if (hfp_send_brsf(hfp, &hfp_our_brsf)  || msg_queue_push(pvt, AT_BRSF, AT_BRSF)) {
@@ -3419,10 +3853,7 @@ static void *do_monitor_phone(void *data)
                }
 
                if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
-                       /* XXX gnu specific strerror_r is assummed here, this
-                        * is not really safe.  See the strerror(3) man page
-                        * for more info. */
-                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
+                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
                        break;
                }
 
@@ -3510,6 +3941,48 @@ static void *do_monitor_phone(void *data)
                        }
                        ast_mutex_unlock(&pvt->lock);
                        break;
+               case AT_CUSD:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_cusd(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_BUSY:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_busy(pvt)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_NO_DIALTONE:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_no_dialtone(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_NO_CARRIER:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_no_carrier(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_ECAM:
+                       ast_mutex_lock(&pvt->lock);
+                       if (hfp_parse_ecav(hfp, buf) == 7) {
+                               if (handle_response_busy(pvt)) {
+                                       ast_mutex_unlock(&pvt->lock);
+                                       goto e_cleanup;
+                               }
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
                case AT_UNKNOWN:
                        ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
                        break;
@@ -3517,7 +3990,7 @@ static void *do_monitor_phone(void *data)
                        ast_debug(1, "[%s] error parsing message\n", pvt->id);
                        goto e_cleanup;
                case AT_READ_ERROR:
-                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
+                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
                        goto e_cleanup;
                default:
                        break;
@@ -3595,11 +4068,7 @@ static void *do_monitor_headset(void *data)
                        continue;
 
                if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
-                       if (strerror_r(errno, buf, sizeof(buf)))
-                               ast_debug(1, "[%s] error reading from device\n", pvt->id);
-                       else
-                               ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno);
-
+                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
                        goto e_cleanup;
                }
                ast_debug(1, "[%s] %s\n", pvt->id, buf);
@@ -3661,7 +4130,7 @@ static void *do_monitor_headset(void *data)
 
                                pvt->incoming = 1;
 
-                               if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL))) {
+                               if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL, NULL))) {
                                        ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
                                        ast_mutex_unlock(&pvt->lock);
                                        goto e_cleanup;
@@ -3669,7 +4138,7 @@ static void *do_monitor_headset(void *data)
 
                                ast_channel_set_fd(chan, 0, pvt->sco_socket);
 
-                               ast_copy_string(chan->exten, "s", AST_MAX_EXTENSION);
+                               ast_channel_exten_set(chan, "s");
                                if (ast_pbx_start(chan)) {
                                        ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
                                        ast_hangup(chan);
@@ -3757,7 +4226,7 @@ static void *do_discovery(void *data)
                                                                pvt->connected = 1;
                                                                adapter->inuse = 1;
                                                                manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id);
-                                                               ast_verb(3, "Bluetooth Device %s has connected, initilizing...\n", pvt->id);
+                                                               ast_verb(3, "Bluetooth Device %s has connected, initializing...\n", pvt->id);
                                                        }
                                                }
                                        }
@@ -3785,18 +4254,17 @@ static void *do_discovery(void *data)
 static void *do_sco_listen(void *data)
 {
        struct adapter_pvt *adapter = (struct adapter_pvt *) data;
-       int res;
 
        while (!check_unloading()) {
                /* check for new sco connections */
-               if ((res = ast_io_wait(adapter->accept_io, 0)) == -1) {
+               if (ast_io_wait(adapter->accept_io, 0) == -1) {
                        /* handle errors */
                        ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
                        break;
                }
 
                /* handle audio data */
-               if ((res = ast_io_wait(adapter->io, 1)) == -1) {
+               if (ast_io_wait(adapter->io, 1) == -1) {
                        ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
                        break;
                }
@@ -3994,6 +4462,7 @@ static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
        pvt->sco_socket = -1;
        pvt->monitor_thread = AST_PTHREADT_NULL;
        pvt->ring_sched_id = -1;
+       pvt->has_sms = 1;
 
        /* setup the smoother */
        if (!(pvt->smoother = ast_smoother_new(DEVICE_FRAME_SIZE))) {
@@ -4008,7 +4477,7 @@ static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
        }
 
        /* setup the scheduler */
-       if (!(pvt->sched = sched_context_create())) {
+       if (!(pvt->sched = ast_sched_context_create())) {
                ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
                goto e_free_dsp;
        }
@@ -4027,6 +4496,8 @@ static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
                } else if (!strcasecmp(v->name, "group")) {
                        /* group is set to 0 if invalid */
                        pvt->group = atoi(v->value);
+               } else if (!strcasecmp(v->name, "sms")) {
+                       pvt->has_sms = ast_true(v->value);
                } else if (!strcasecmp(v->name, "nocallsetup")) {
                        pvt->no_callsetup = ast_true(v->value);
 
@@ -4034,6 +4505,7 @@ static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
                                ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
                } else if (!strcasecmp(v->name, "blackberry")) {
                        pvt->blackberry = ast_true(v->value);
+                       pvt->has_sms = 0;
                }
        }
 
@@ -4046,6 +4518,8 @@ static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
                pvt->hfp->owner = pvt;
                pvt->hfp->rport = pvt->rfcomm_port;
                pvt->hfp->nocallsetup = pvt->no_callsetup;
+       } else {
+               pvt->has_sms = 0;
        }
 
        AST_RWLIST_WRLOCK(&devices);
@@ -4056,7 +4530,7 @@ static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
        return pvt;
 
 e_free_sched:
-       sched_context_destroy(pvt->sched);
+       ast_sched_context_destroy(pvt->sched);
 e_free_dsp:
        ast_dsp_free(pvt->dsp);
 e_free_smoother:
@@ -4075,6 +4549,9 @@ static int mbl_load_config(void)
        struct ast_flags config_flags = { 0 };
 
        cfg = ast_config_load(MBL_CONFIG, config_flags);
+       if (!cfg) {
+               cfg = ast_config_load(MBL_CONFIG_OLD, config_flags);
+       }
        if (!cfg)
                return -1;
 
@@ -4191,7 +4668,7 @@ static int unload_module(void)
 
                ast_smoother_free(pvt->smoother);
                ast_dsp_free(pvt->dsp);
-               sched_context_destroy(pvt->sched);
+               ast_sched_context_destroy(pvt->sched);
                ast_free(pvt);
        }
        AST_RWLIST_UNLOCK(&devices);
@@ -4210,6 +4687,8 @@ static int unload_module(void)
        if (sdp_session)
                sdp_close(sdp_session);
 
+       ao2_ref(mbl_tech.capabilities, -1);
+       mbl_tech.capabilities = NULL;
        return 0;
 }
 
@@ -4218,11 +4697,20 @@ static int load_module(void)
 
        int dev_id, s;
 
+       if (!(mbl_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
+       ast_format_cap_append(mbl_tech.capabilities, DEVICE_FRAME_FORMAT, 0);
        /* Check if we have Bluetooth, no point loading otherwise... */
        dev_id = hci_get_route(NULL);
+
        s = hci_open_dev(dev_id);
        if (dev_id < 0 || s < 0) {
                ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
+               ao2_ref(mbl_tech.capabilities, -1);
+               mbl_tech.capabilities = NULL;
+               hci_close_dev(s);
                return AST_MODULE_LOAD_DECLINE;
        }
 
@@ -4230,6 +4718,8 @@ static int load_module(void)
 
        if (mbl_load_config()) {
                ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
+               ao2_ref(mbl_tech.capabilities, -1);
+               mbl_tech.capabilities = NULL;
                return AST_MODULE_LOAD_DECLINE;
        }
 
@@ -4254,13 +4744,14 @@ static int load_module(void)
        return AST_MODULE_LOAD_SUCCESS;
 
 e_cleanup:
-       if (sdp_session)
-               sdp_close(sdp_session);
+       unload_module();
 
-       return AST_MODULE_LOAD_FAILURE;
+       return AST_MODULE_LOAD_DECLINE;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bluetooth Mobile Device Channel Driver",
-               .load = load_module,
-               .unload = unload_module,
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver",
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 );