* [PATCH 15/26] Implement function to send md_create_mdl_req
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-15-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 177 insertions(+), 0 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 064919e..7a32e68 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -34,6 +34,7 @@
#include "mcap_lib.h"
#include "mcap_internal.h"
+#define RESPONSE_TIMER 2 /* seconds */
#define MAX_CACHED 10 /* 10 devices */
#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
@@ -49,6 +50,17 @@ struct connect_mcl {
gpointer user_data; /* Callback user data */
};
+typedef union {
+ mcap_mdl_operation_cb op;
+ mcap_mdl_operation_conf_cb op_conf;
+ mcap_mdl_del_cb del;
+} mcap_cb_type;
+
+struct mcap_mdl_op_cb {
+ struct mcap_mdl *mdl; /* MDL for this operation */
+ mcap_cb_type cb; /* Operation callback */
+ gpointer user_data; /* Callback user data */
+};
/* MCAP finite state machine functions */
static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -61,6 +73,8 @@ static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
proc_req_active
};
+static void mcap_cache_mcl(struct mcap_mcl *mcl);
+
static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
{
DBG("MCAP Unmanaged mdl connection");
@@ -111,6 +125,67 @@ static void set_default_cb(struct mcap_mcl *mcl)
mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
}
+static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t size, GError **err)
+{
+ if (mcl->state == MCL_IDLE) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "MCL is not connected");
+ return;
+ }
+
+ if (mcl->req != MCL_AVAILABLE) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
+ "Pending request");
+ return;
+ }
+
+ if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+ "Remote does not support standard opcodes");
+ return;
+ }
+
+ if (mcl->state == MCL_PENDING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
+ "Not Std Op. Codes can be sent in PENDING State");
+ return;
+ }
+
+ if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Command can't be sent, write error");
+ return;
+ }
+
+ mcl->lcmd = cmd;
+ mcl->req = MCL_WAITING_RSP;
+}
+
+static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
+{
+ struct mcap_mdl_op_cb *con = mcl->priv_data;
+
+ if (!con || !mcl->lcmd)
+ return;
+
+ switch (mcl->lcmd[0]){
+ case MCAP_MD_CREATE_MDL_REQ:
+ con->cb.op_conf(NULL, 0, err, con->user_data);
+ break;
+ case MCAP_MD_ABORT_MDL_REQ:
+ case MCAP_MD_DELETE_MDL_REQ:
+ con->cb.del(err, con->user_data);
+ break;
+ case MCAP_MD_RECONNECT_MDL_REQ:
+ con->cb.op(NULL, err, con->user_data);
+ break;
+ }
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+}
+
int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
{
uint32_t sent = 0;
@@ -167,6 +242,42 @@ static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
return sent;
}
+static uint16_t generate_mdlid(struct mcap_mcl *mcl)
+{
+ uint16_t mdlid = MCAP_MDLID_INITIAL;
+ struct mcap_mdl *mdl;
+ GSList *l;
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdlid < mdl->mdlid)
+ break;
+ else
+ mdlid = mdl->mdlid + 1;
+ }
+
+ if (mdlid > MCAP_MDLID_FINAL)
+ return 0;
+
+ return mdlid;
+}
+
+static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
+{
+ uint8_t *req;
+ mcap_md_create_mdl_req *req_mdl;
+
+ req = g_malloc0(sizeof(mcap_md_create_mdl_req));
+
+ req_mdl = (mcap_md_create_mdl_req *)req;
+ req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
+ req_mdl->mdl = htons(mdl_id);
+ req_mdl->mdep = mdep;
+ req_mdl->conf = conf;
+
+ return req;
+}
+
static gint compare_mdl(gconstpointer a, gconstpointer b)
{
const struct mcap_mdl *mdla = a;
@@ -180,6 +291,72 @@ static gint compare_mdl(gconstpointer a, gconstpointer b)
return 1;
}
+static gboolean wait_response_timer(gpointer data)
+{
+ struct mcap_mcl *mcl = data;
+
+ GError *gerr = NULL;
+
+ RELEASE_TIMER(mcl);
+
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Timeout waiting response");
+
+ mcap_notify_error(mcl, gerr);
+
+ g_error_free(gerr);
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
+ return FALSE;
+}
+
+void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+ uint8_t mdepid,
+ uint8_t conf,
+ GError **err,
+ mcap_mdl_operation_conf_cb connect_cb,
+ gpointer user_data)
+{
+ struct mcap_mdl *mdl;
+ struct mcap_mdl_op_cb *con;
+ uint8_t *cmd = NULL;
+ uint16_t id;
+
+ id = generate_mdlid(mcl);
+ if (!id) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Not more mdlids available");
+ return;
+ }
+
+ mdl = g_new0(struct mcap_mdl, 1);
+ mdl->mcl = mcl;
+ mdl->mdlid = id;
+ mdl->mdep_id = mdepid;
+ mdl->state = MDL_WAITING;
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = mdl;
+ con->cb.op_conf = connect_cb;
+ con->user_data = user_data;
+
+ cmd = create_mdl_req(id, mdepid, conf);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req), err);
+ if (*err) {
+ g_free(mdl);
+ g_free(con);
+ g_free(cmd);
+ return;
+ }
+
+ mcl->state = MCL_ACTIVE;
+ mcl->priv_data = con;
+
+ mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 16/26] Implement function to send md_reconnect_mdl_req
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-16-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 7a32e68..2feac10 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -262,6 +262,20 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
return mdlid;
}
+static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
+{
+ uint8_t *req;
+ mcap_md_req *req_cmd;
+
+ req = g_malloc0(sizeof(mcap_md_req));
+
+ req_cmd = (mcap_md_req *)req;
+ req_cmd->op = op;
+ req_cmd->mdl = htons(mdl_id);
+
+ return req;
+}
+
static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
{
uint8_t *req;
@@ -357,6 +371,43 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
mcl);
}
+void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
+ GError **err,
+ mcap_mdl_operation_cb reconnect_cb,
+ gpointer user_data)
+{
+ struct mcap_mdl_op_cb *con;
+ struct mcap_mcl *mcl = mdl->mcl;
+ uint8_t *cmd;
+
+ if (mdl->state != MDL_CLOSED) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "MDL is not closed");
+ return;
+ }
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+
+ cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+ if (*err) {
+ g_free(con);
+ g_free(cmd);
+ return;
+ }
+
+ mdl->state = MDL_WAITING;
+
+ con->mdl = mdl;
+ con->cb.op = reconnect_cb;
+ con->user_data = user_data;
+
+ mcl->state = MCL_ACTIVE;
+ mcl->priv_data = con;
+
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 17/26] Implement function to send md_delete_mdl_req
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-17-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 112 insertions(+), 0 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 2feac10..2c03e83 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -125,6 +125,38 @@ static void set_default_cb(struct mcap_mcl *mcl)
mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
}
+static char *error2str(uint8_t rc)
+{
+ switch (rc) {
+ case MCAP_SUCCESS:
+ return "Success";
+ case MCAP_INVALID_OP_CODE:
+ return "Invalid Op Code";
+ case MCAP_INVALID_PARAM_VALUE:
+ return "Invalid Parameter Value";
+ case MCAP_INVALID_MDEP:
+ return "Invalid MDEP";
+ case MCAP_MDEP_BUSY:
+ return "MDEP Busy";
+ case MCAP_INVALID_MDL:
+ return "Invalid MDL";
+ case MCAP_MDL_BUSY:
+ return "MDL Busy";
+ case MCAP_INVALID_OPERATION:
+ return "Invalid Operation";
+ case MCAP_RESOURCE_UNAVAILABLE:
+ return "Resource Unavailable";
+ case MCAP_UNSPECIFIED_ERROR:
+ return "Unspecified Error";
+ case MCAP_REQUEST_NOT_SUPPORTED:
+ return "Request Not Supported";
+ case MCAP_CONFIGURATION_REJECTED:
+ return "Configuration Rejected";
+ default:
+ return "Unknown Response Code";
+ }
+}
+
static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t size, GError **err)
{
@@ -408,6 +440,86 @@ void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
mcl);
}
+static void send_delete_req(GError **err, struct mcap_mcl *mcl,
+ struct mcap_mdl_op_cb *con, uint16_t mdlid)
+{
+ uint8_t *cmd;
+
+ cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+ if (*err) {
+ g_free(cmd);
+ return;
+ }
+
+ mcl->priv_data = con;
+
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
+ mcap_mdl_del_cb delete_cb, gpointer user_data)
+{
+ GSList *l;
+ struct mcap_mdl *mdl;
+ struct mcap_mdl_op_cb *con;
+
+ DBG("MCL in state: %d", mcl->state);
+ if (!mcl->mdls) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "There are not MDLs created");
+ return;
+ }
+
+ for (l = mcl->mdls; l; l = l->next) {
+ mdl = l->data;
+ if (mdl->state != MDL_WAITING)
+ mdl->state = MDL_DELETING;
+ }
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = NULL;
+ con->cb.del = delete_cb;
+ con->user_data = user_data;
+
+ send_delete_req(err, mcl, con, MCAP_ALL_MDLIDS);
+ if (*err)
+ g_free(con);
+}
+
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_del_cb delete_cb, gpointer user_data)
+{
+ struct mcap_mcl *mcl= mdl->mcl;
+ struct mcap_mdl_op_cb *con;
+ GSList *l;
+
+ l = g_slist_find(mcl->mdls, mdl);
+
+ if (!l) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
+ "%s" , error2str(MCAP_INVALID_MDEP));
+ return;
+ }
+
+ if (mdl->state == MDL_WAITING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Mdl is not created");
+ return;
+ }
+ mdl->state = MDL_DELETING;
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = mdl;
+ con->cb.del = delete_cb;
+ con->user_data = user_data;
+
+ send_delete_req(err, mcl, con, mdl->mdlid);
+ if (*err)
+ g_free(con);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 18/26] Implement function to send md_abort_mdl_req
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-18-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 48 insertions(+), 0 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 2c03e83..78b6af8 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -520,6 +520,38 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
g_free(con);
}
+void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
+ mcap_mdl_del_cb abort_cb, gpointer user_data)
+{
+ struct mcap_mdl_op_cb *con;
+ struct mcap_mcl *mcl = mdl->mcl;
+ uint8_t *cmd;
+
+ if (mdl->state != MDL_WAITING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Mdl in invalid state");
+ return;
+ }
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
+ mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+ if (*err) {
+ g_free(con);
+ g_free(cmd);
+ return;
+ }
+
+ con->mdl = mdl;
+ con->cb.del = abort_cb;
+ con->user_data = user_data;
+
+ mcl->priv_data = con;
+
+ mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+ mcl);
+}
+
static void update_mcl_state(struct mcap_mcl *mcl)
{
GSList *l;
@@ -555,6 +587,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
return NULL;
}
+int mcap_mdl_get_fd(struct mcap_mdl *mdl)
+{
+ if ((!mdl) || (mdl->state != MDL_CONNECTED))
+ return -1;
+
+ return g_io_channel_unix_get_fd(mdl->dc);
+}
+
+uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
+{
+ if (!mdl)
+ return MCAP_MDLID_RESERVED;
+
+ return mdl->mdlid;
+}
+
static void shutdown_mdl(struct mcap_mdl *mdl)
{
mdl->state = MDL_CLOSED;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 19/26] Process response to std. op. codes
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-19-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 140 insertions(+), 1 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 78b6af8..cd710da 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1171,9 +1171,112 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}
}
+static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
+ uint8_t *cmd, uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
+ uint8_t *cmd, uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
+ uint8_t *cmd, uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
+ uint32_t len)
+{
+ return FALSE;
+}
+
+static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ mcap4B_rsp *rsp;
+ GError *gerr = NULL;
+
+ /* Check if the response matches with the last request */
+ if ((cmd[0] != MCAP_ERROR_RSP) && ((mcl->lcmd[0] + 1) != cmd[0]))
+ goto close_mcl;
+
+ if (len < 4)
+ goto close_mcl;
+
+ rsp = (mcap4B_rsp *)cmd;
+
+ if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) {
+ DBG("Remote does not support opcodes");
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+ "%s", error2str(rsp->rc));
+ mcap_notify_error(mcl, gerr);
+ g_error_free(gerr);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->ctrl &= ~MCAP_CTRL_STD_OP;
+ mcl->req = MCL_AVAILABLE;
+ update_mcl_state(mcl);
+ return FALSE;
+ }
+
+ if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
+ goto close_mcl;
+
+ return TRUE;
+close_mcl:
+ if (rsp->rc == MCAP_UNSPECIFIED_ERROR)
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_UNSPECIFIED_ERROR,
+ "%s", error2str(rsp->rc));
+ else
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Protocol error");
+ mcap_notify_error(mcl, gerr);
+ g_error_free(gerr);
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
+ return FALSE;
+}
+
static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
- /* TODO */
+ gboolean close;
+ RELEASE_TIMER(mcl);
+
+ if (!check_rsp(mcl, cmd, len))
+ return;
+
+ switch (cmd[0]) {
+ case MCAP_ERROR_RSP:
+ error("MCAP_ERROR_RSP received");
+ close = TRUE;
+ break;
+ case MCAP_MD_CREATE_MDL_RSP:
+ close = process_md_create_mdl_rsp(mcl, cmd, len);
+ break;
+ case MCAP_MD_RECONNECT_MDL_RSP:
+ close = process_md_reconnect_mdl_rsp(mcl, cmd, len);
+ break;
+ case MCAP_MD_ABORT_MDL_RSP:
+ close = process_md_abort_mdl_rsp(mcl, cmd, len);
+ break;
+ case MCAP_MD_DELETE_MDL_RSP:
+ close = process_md_delete_mdl_rsp(mcl, cmd, len);
+ break;
+ default:
+ DBG("Unknown cmd response received (op code = %d)",cmd[0]);
+ close = TRUE;
+ break;
+ }
+
+ if (close) {
+ mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+ mcap_cache_mcl(mcl);
+ }
}
static void rsend_req(struct mcap_mcl *mcl)
@@ -1631,3 +1734,39 @@ void mcap_release_instance(struct mcap_instance *ms)
g_free(ms);
}
+
+uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err)
+{
+ uint16_t lpsm;
+
+ if (!(ms && ms->ccio)) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "Invalid MCAP instance");
+ return 0;
+ }
+
+ bt_io_get(ms->ccio, BT_IO_L2CAP, err,
+ BT_IO_OPT_PSM, &lpsm,
+ BT_IO_OPT_INVALID);
+ if (*err)
+ return 0;
+ return lpsm;
+}
+
+uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err)
+{
+ uint16_t lpsm;
+
+ if (!(ms && ms->dcio)) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+ "Invalid MCAP instance");
+ return 0;
+ }
+
+ bt_io_get(ms->dcio, BT_IO_L2CAP, err,
+ BT_IO_OPT_PSM, &lpsm,
+ BT_IO_OPT_INVALID);
+ if (*err)
+ return 0;
+ return lpsm;
+}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 20/26] Process md_create_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-20-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 79 insertions(+), 1 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index cd710da..4708fe7 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1171,10 +1171,88 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
}
}
+/* Function used to process replies */
+static gboolean check_err_rsp(uint16_t rmdl, uint16_t smdl, uint8_t rc,
+ uint32_t rlen, uint32_t len, GError **gerr)
+{
+ gboolean close = FALSE;
+ char *msg;
+ gint err = MCAP_ERROR_FAILED;
+
+ if (rmdl != smdl) {
+ msg = "MDLID received doesn't match with MDLID sent";
+ close = TRUE;
+ goto fail;
+ }
+
+ if ((rc != MCAP_SUCCESS) && (rc <= MCAP_CONFIGURATION_REJECTED)) {
+ msg = error2str(rc);
+ err = rc;
+ goto fail;
+ }
+
+ if (rlen < len) {
+ msg = "Protocol error";
+ close = TRUE;
+ goto fail;
+ }
+ return FALSE;
+fail:
+ g_set_error(gerr, MCAP_ERROR, err, "%s", msg);
+ return close;
+}
+
static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *conn = mcl->priv_data;
+ struct mcap_mdl *mdl = conn->mdl;
+ mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf;
+ gpointer user_data = conn->user_data;
+ uint16_t mdlid;
+ mcap5B_rsp *rsp = (mcap5B_rsp *) cmd;
+ mcap_md_create_mdl_req *cmdlast;
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd;
+ mdlid = ntohs(cmdlast->mdl);
+ rsp->mdl = ntohs(rsp->mdl);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, 0, 0, &gerr);
+
+ if (gerr)
+ goto fail;
+
+ if (len < 5) {
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Protocol error");
+ close = TRUE;
+ goto fail;
+ }
+
+ /* Check if preferences changed */
+ if ((cmdlast->conf != 0x00) && (rsp->param != cmdlast->conf)) {
+ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+ "Configuration changed");
+ close = TRUE;
+ goto fail;
+ }
+
+ connect_cb(mdl, rsp->param, gerr, user_data);
+ return close;
+fail:
+ connect_cb(NULL, 0, gerr, user_data);
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
+ g_error_free(gerr);
+ return close;
}
static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
--
1.6.3.3
^ permalink raw reply related
* [PATCH 21/26] Process md_reconnect_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-21-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 38 insertions(+), 1 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 4708fe7..bd22d54 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1258,7 +1258,44 @@ fail:
static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *reconn = mcl->priv_data;
+ struct mcap_mdl *mdl = reconn->mdl;
+ mcap_mdl_operation_cb reconn_cb = reconn->cb.op;
+ gpointer user_data = reconn->user_data;
+ mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ uint16_t mdlid = ntohs(cmdlast->mdl);
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ rsp->mdl = ntohs(rsp->mdl);
+
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
+ sizeof(mcap4B_rsp), &gerr);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+
+ reconn_cb(mdl, gerr, user_data);
+ if (!gerr)
+ return close;
+
+ g_error_free(gerr);
+ shutdown_mdl(mdl);
+
+ if (rsp->rc != MCAP_INVALID_MDL)
+ return close;
+
+ /* Remove cached mdlid */
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ mcl->cb->mdl_deleted(mdl, mcl->cb->user_data);
+ g_free(mdl);
+
+ return close;
}
static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
--
1.6.3.3
^ permalink raw reply related
* [PATCH 22/26] Process md_abort_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-22-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 33 ++++++++++++++++++++++++++++++++-
1 files changed, 32 insertions(+), 1 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index bd22d54..17f0573 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1301,7 +1301,38 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl,
static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
uint8_t *cmd, uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *abrt = mcl->priv_data;
+ struct mcap_mdl *mdl = abrt->mdl;
+ mcap_mdl_del_cb abrt_cb = abrt->cb.del;
+ gpointer user_data = abrt->user_data;
+ mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ uint16_t mdlid = ntohs(cmdlast->mdl);
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ rsp->mdl = ntohs(rsp->mdl);
+
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
+ sizeof(mcap4B_rsp), &gerr);
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+
+ if (gerr) {
+ abrt_cb(gerr, user_data);
+ g_error_free(gerr);
+ return close;
+ }
+
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ g_free(mdl);
+ update_mcl_state(mcl);
+ abrt_cb(gerr, user_data);
+ return close;
}
static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
--
1.6.3.3
^ permalink raw reply related
* [PATCH 23/26] Process md_delete_mdl_rsp
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-23-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 59 insertions(+), 1 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 17f0573..26eb7b9 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1335,10 +1335,68 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl,
return close;
}
+static void restore_mdl(gpointer elem, gpointer data)
+{
+ struct mcap_mdl *mdl = elem;
+
+ if (mdl->state == MDL_DELETING) {
+ if (mdl->dc)
+ mdl->state = MDL_CONNECTED;
+ else
+ mdl->state = MDL_CLOSED;
+ } else if (mdl->state == MDL_CLOSED)
+ mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
+}
+
static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd,
uint32_t len)
{
- return FALSE;
+ struct mcap_mdl_op_cb *del = mcl->priv_data;
+ struct mcap_mdl *mdl = del->mdl;
+ mcap_mdl_del_cb deleted_cb = del->cb.del;
+ gpointer user_data = del->user_data;
+ mcap4B_rsp *rsp = (mcap4B_rsp *) cmd;
+ mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
+ uint16_t mdlid = ntohs(cmdlast->mdl);
+ GError *gerr = NULL;
+ gboolean close = FALSE;
+ gboolean notify = FALSE;
+
+ g_free(mcl->priv_data);
+ mcl->priv_data = NULL;
+
+ rsp->mdl = ntohs(rsp->mdl);
+
+ close = check_err_rsp(rsp->mdl, mdlid, rsp->rc, len,
+ sizeof(mcap4B_rsp), &gerr);
+
+ g_free(mcl->lcmd);
+ mcl->lcmd = NULL;
+ mcl->req = MCL_AVAILABLE;
+ if (gerr) {
+ if (mdl)
+ restore_mdl(mdl, NULL);
+ else
+ g_slist_foreach(mcl->mdls, restore_mdl, NULL);
+ deleted_cb(gerr, user_data);
+ g_error_free(gerr);
+ return close;
+ }
+
+ if (mdlid == MCAP_ALL_MDLIDS) {
+ g_slist_foreach(mcl->mdls, mcap_delete_mdl, ¬ify);
+ g_slist_free(mcl->mdls);
+ mcl->mdls = NULL;
+ mcl->state = MCL_CONNECTED;
+ goto end;
+ }
+
+ mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+ update_mcl_state(mcl);
+ mcap_delete_mdl(mdl, ¬ify);
+end:
+ deleted_cb(gerr, user_data);
+ return close;
}
static gboolean check_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
--
1.6.3.3
^ permalink raw reply related
* [PATCH 24/26] Enable connection of Data Channel with remote MCAP instances
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-24-git-send-email-sancane@gmail.com>
---
mcap/mcap.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 26eb7b9..656b254 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1558,6 +1558,66 @@ static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
return FALSE;
}
+static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err,
+ gpointer data)
+{
+ struct mcap_mdl_op_cb *con = data;
+ struct mcap_mdl *mdl = con->mdl;
+ mcap_mdl_operation_cb cb = con->cb.op;
+ gpointer user_data = con->user_data;
+
+ g_free(con);
+ DBG("mdl connect callback");
+
+ if (conn_err) {
+ DBG("ERROR: mdl connect callback");
+ mdl->state = MDL_CLOSED;
+ g_io_channel_unref(mdl->dc);
+ mdl->dc = NULL;
+ cb(mdl, conn_err, user_data);
+ return;
+ }
+
+ mdl->state = MDL_CONNECTED;
+ mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) mdl_event_cb, mdl);
+
+ cb(mdl, conn_err, user_data);
+}
+
+void mcap_mdl_connect(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm,
+ GError **err, mcap_mdl_operation_cb connect_cb, gpointer user_data)
+{
+ struct mcap_mdl_op_cb *con;
+
+ if (mdl->state != MDL_WAITING) {
+ g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
+ "%s", error2str(MCAP_INVALID_MDL));
+ return;
+ }
+
+ con = g_new0(struct mcap_mdl_op_cb, 1);
+ con->mdl = mdl;
+ con->cb.op = connect_cb;
+ con->user_data = user_data;
+
+ /* TODO: Check if BtIOType is ERTM or Streaming before continue */
+
+ mdl->dc = bt_io_connect(BtType, mcap_connect_mdl_cb, con,
+ NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->ms->src,
+ BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr,
+ BT_IO_OPT_PSM, dcpsm,
+ BT_IO_OPT_MTU, MCAP_DC_MTU,
+ BT_IO_OPT_SEC_LEVEL, mdl->mcl->ms->sec,
+ BT_IO_OPT_INVALID);
+ if (*err) {
+ DBG("MDL Connection error");
+ mdl->state = MDL_CLOSED;
+ g_free(con);
+ }
+}
+
static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
--
1.6.3.3
^ permalink raw reply related
* [PATCH 25/26] Initial support for clock synchronization protocol
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-25-git-send-email-sancane@gmail.com>
---
Makefile.am | 4 +-
mcap/mcap.c | 3 +-
mcap/sync.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 4 deletions(-)
create mode 100644 mcap/sync.c
diff --git a/Makefile.am b/Makefile.am
index 93566b6..f96d556 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -170,8 +170,8 @@ builtin_sources += plugins/service.c
endif
if MCAP
-mcap_sources += mcap/mcap_internal.h \
- mcap/mcap_lib.h \
+mcap_sources += mcap/mcap_internal.h \
+ mcap/mcap_lib.h mcap/sync.c \
mcap/mcap.h mcap/mcap.c
endif
diff --git a/mcap/mcap.c b/mcap/mcap.c
index 656b254..d907eca 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -1511,8 +1511,7 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
{
if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
(cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
- send4B_cmd(mcl, cmd[0], MCAP_REQUEST_NOT_SUPPORTED,
- MCAP_MDLID_RESERVED);
+ proc_sync_cmd(mcl, cmd, len);
return;
}
diff --git a/mcap/sync.c b/mcap/sync.c
new file mode 100644
index 0000000..76f1377
--- /dev/null
+++ b/mcap/sync.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * Authors:
+ * Santiago Carot-Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+#include "log.h"
+
+#include "mcap.h"
+#include "mcap_lib.h"
+#include "mcap_internal.h"
+
+static int send_unsupported_req(struct mcap_mcl *mcl, uint8_t oc)
+{
+ uint8_t *rsp;
+ mcap4B_rsp *rsp_err;
+ int sent;
+
+
+ rsp = g_malloc0(sizeof(mcap4B_rsp));
+
+ rsp_err = (mcap4B_rsp *)rsp;
+ rsp_err->op = oc;
+ rsp_err->rc = MCAP_REQUEST_NOT_SUPPORTED;
+ rsp_err->mdl = htons (MCAP_MDLID_RESERVED);
+
+ sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
+ rsp,
+ sizeof(mcap4B_rsp));
+ g_free(rsp);
+ return sent;
+}
+
+void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+ switch (cmd[0]) {
+ case MCAP_MD_SYNC_CAP_REQ:
+ DBG("TODO: received MCAP_MD_SYNC_CAP_REQ: %d",
+ MCAP_MD_SYNC_CAP_REQ);
+ /* Not implemented yet. Reply with unsupported request */
+ send_unsupported_req(mcl, cmd[0]);
+ break;
+ case MCAP_MD_SYNC_CAP_RSP:
+ DBG("TODO: received MCAP_MD_SYNC_CAP_RSP: %d",
+ MCAP_MD_SYNC_CAP_RSP);
+ break;
+ case MCAP_MD_SYNC_SET_REQ:
+ DBG("TODO: received MCAP_MD_SYNC_SET_REQ: %d",
+ MCAP_MD_SYNC_SET_REQ);
+ /* Not implemented yet. Reply with unsupported request */
+ send_unsupported_req(mcl, cmd[0]);
+ break;
+ case MCAP_MD_SYNC_SET_RSP:
+ DBG("TODO: received MCAP_MD_SYNC_SET_RSP: %d",
+ MCAP_MD_SYNC_SET_RSP);
+ break;
+ case MCAP_MD_SYNC_INFO_IND:
+ DBG("TODO: received MCAP_MD_SYNC_INFO_IND :%d",
+ MCAP_MD_SYNC_INFO_IND);
+ break;
+ }
+}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 26/26] Free memory when a unref operation happens over a cached MCL
From: Santiago Carot-Nemesio @ 2010-06-04 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1275640039-7245-26-git-send-email-sancane@gmail.com>
MCAP should free memory in cached MCL list if an unref operation
happens over a cached MCL and only MCAP has a local copy of it.
MCL is removed from cached list and memory resources are freed.
---
mcap/mcap.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/mcap/mcap.c b/mcap/mcap.c
index d907eca..b2e4946 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -780,6 +780,15 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
+ if ((mcl->ctrl & MCAP_CTRL_CACHED) && (mcl->ref < 2)) {
+ /* Free space in cache memory due any other profile has a local
+ * copy of current MCL stored in cache */
+ DBG("Remove from cache (%p): ref=%d", mcl, mcl->ref);
+ mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
+ mcap_mcl_release(mcl);
+ return;
+ }
+
if (mcl->ref > 0)
return;
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH v3] Change MDP profile name and macros to HDP
From: Johan Hedberg @ 2010-06-04 8:27 UTC (permalink / raw)
To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <1275422058-16172-1-git-send-email-epx@signove.com>
Hi Elvis,
On Tue, Jun 01, 2010, Elvis Pfützenreuter wrote:
> ---
> lib/sdp.c | 6 +++---
> lib/sdp.h | 22 ++++++++++++++++------
> tools/sdptool.c | 6 +++---
> 3 files changed, 22 insertions(+), 12 deletions(-)
Thanks for the patch. It has now been pushed upstream.
Johan
^ permalink raw reply
* [PATCH 00/32] Health Device Prifile (HDP) -- updated
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth
Next patches, that Santiago Carot-Nemesio and I have developed, are applied
over the MCAP patches previously sent to the mailing list.
This a first patches manage the creation of links beetween instances and
begins the support for creating data chanels, but doesn't finish it yet.
Also new debug features are used.
You could find a branch with all the patches (MCAP/HDP) applied here:
git://gitorious.org/bluez-mcap-hdp/bluez-mcap-hdp.git
Regards
^ permalink raw reply
* [PATCH 01/32] Add Health api description
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-1-git-send-email-santoscadenas@gmail.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 7156 bytes --]
This API describes the interface shown by the Health plugin through d-bus
---
doc/health-api.txt | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 217 insertions(+), 0 deletions(-)
create mode 100644 doc/health-api.txt
diff --git a/doc/health-api.txt b/doc/health-api.txt
new file mode 100644
index 0000000..83e29af
--- /dev/null
+++ b/doc/health-api.txt
@@ -0,0 +1,217 @@
+BlueZ D-Bus Health API description
+**********************************
+
+ Santiago Carot-Nemesio <sancane@gmail.com>
+ José Antonio Santos-Cadenas <santoscadenas@gmail.com>
+ Elvis Pfützenreuter <epx@signove.com>
+
+Health Device Profile hierarchy
+===============================
+
+Service org.bluez
+Interface org.bluez.HealthAdapter
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods:
+
+ uint32 CreateInstance(object path, dict config)
+
+ Returns the id of the new created instance. The path parameter
+ is the path of the remote object with the callbacks to notify
+ events (see org.bluez.HealthAgent at the end of this document)
+ This petition starts an mcap instance and also register in the
+ SDP if is needed.
+
+ Dict is defined as bellow:
+ { "data_spec" : The data_spec is the data exchange specification
+ (see section 5.2.10 of the specification
+ document) possible values:
+ 0x00 = reserved,
+ 0x01 [IEEE 11073-20601],
+ 0x02..0xff reserved,
+ (optional)
+ "end_points" : [{ (optional)
+ "mdepid" : uint8, (optional)
+ "role" : ("source" or "sink"), (mandatory)
+ "specs" :[{ (mandatory)
+ "data_type" : uint16, (mandatory)
+ "description" : string, (optional)
+ }]
+ }]
+ }
+
+ if "data_spec" is not set, no SDP record will be registered, so
+ all the other data in the dictionary will be ignored.
+
+ Instance will be closed by the call or implicitly when the
+ programs leaves the bus.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ void CloseInstance(uint32 )
+
+ Closes the HDP instance identified by the object path. Also
+ instance will be closed if the process that started leaves the
+ bus. If there is a SDP record associated to this instance it
+ will be removed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthDevice
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods:
+
+ array GetHealthInstances()
+
+ Gets the information of the remote instances present in this
+ device and published on its SDP record. The returned data
+ follows this format.
+
+ [{"id": uint32,
+ "data_spec" : data spec,
+ "end_points":
+ ["mdepid": uint8,
+ "role" : "source" or "sink" ,
+ "specs" : [{
+ "dtype" : uint16,
+ "description" : string, (optional)
+ }]
+ ]
+ }];
+
+ object Connect(uint32 local_instance_id, uint32 remote_instance_id)
+
+ Connects the local instance with the remote instance and returns
+ the path of the HealthLink object. You should get the remote
+ instance id running GetHealthInstances.
+
+ Only the bus client that created the local session will be able
+ to create connections using it.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ void Disconnect(object link, boolean cache)
+
+ Disconnect from the link. If cache is false, state will also be
+ deleted. Otherwise, the state will be kept for allowing future
+ reconnections until the adapter holding the local session is
+ removed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthLink
+Object path [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_inst_id
+
+Methods:
+
+ boolean Echo(array{byte})
+
+ Sends an echo petition to the remote intance. Returns True if
+ response matches with the buffer sent. If some error is detected
+ False value is returned and the associated MCL is closed.
+
+ uint16 OpenDataChannel(byte mdepid, byte config)
+
+ Creates a new data channel with the indicated config to the
+ remote MCAP Data End Point (MDEP).
+ The configuration should indicate the channel quality of
+ service. In the current version of HDP, valid values are 0x01
+ for reliable channels and 0x02 for streaming data channel.
+
+ Returns the data channel id.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ array GetDataChannelFileDescriptor(uint16 mdlid)
+
+ Gets a file descriptor where data can be read or
+ written for receive or sent by the data channel.
+ Returns an array of file descriptors one for write
+ and other for read.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+ void DeleteDataChannel(uint16 mdlid)
+
+ Deletes a data channel so it will not be available for
+ use.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+ void DeleteAllDataChannels()
+
+ Deletes all data channels so it will not be available
+ for use. Typically this function is called when the
+ connection with the remote device will be closed
+ permanently
+
+ Possible errors: org.bluez.Error.HealthError
+
+ dict GetDataChannelStatus()
+
+ Return a dictionary with all the data channels that
+ can be used to send data right now. The dictionary
+ is formed like follows:
+ {
+ "reliable": [mdlid_r1, mdlid_r2, ...],
+ "streaming" : [mdlid_s1, mdlid_s2, ...]
+ }
+
+ The fist reliable data channel will always be the first
+ data channel in reliable array.
+
+HealthAgent hierarchy
+=====================
+
+(this object is implemented by the HDP user in order to receive notifications)
+
+Service unique name
+Interface org.bluez.HealthAgent
+Object path freely definable
+
+Methods:
+
+ void LinkConnected(object path)
+
+ This method is called whenever a new connection has been
+ established over the control channel of the current HDP
+ instance. The object path paremeter contains the object path of
+ the created HealthLink.
+
+ void LinkDisconnected(object path)
+
+ This method is called when a remote device is disconnected
+ definitively. Any future reconnections will fail. Also all data
+ channels associated to this device will be closed.
+
+ void CreatedDataChannel(object path, uint16 mdlid, byte conf)
+
+ This method is called when a new data channel is created
+
+ The path contains the object path of the HealthLink where the
+ new connection is created, the mdlid is the data channel
+ identificator and conf is the que quality of service of the data
+ channel (0x01 reliable, 0x02 streaming).
+
+ void DeletedDataChannel(object path, uint16 mdlid)
+
+ This method is called when a data channel is closed.
+
+ After this call the data channel id will not be valid and can be
+ reused for future created data channels.
--
1.6.3.3
^ permalink raw reply related
* [PATCH 02/32] Initial support for HDP
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-2-git-send-email-santoscadenas@gmail.com>
Creates the basic structure of the plugin, registering
adapter and device drivers.
---
Makefile.am | 8 +
acinclude.m4 | 8 +-
health/hdp.c | 183 +++++++++++++++++++++
health/hdp.h | 27 +++
health/hdp_types.h | 99 ++++++++++++
health/hdp_util.c | 447 ++++++++++++++++++++++++++++++++++++++++++++++++++++
health/hdp_util.h | 34 ++++
health/main.c | 60 +++++++
health/manager.c | 101 ++++++++++++
health/manager.h | 27 +++
10 files changed, 993 insertions(+), 1 deletions(-)
create mode 100644 health/hdp.c
create mode 100644 health/hdp.h
create mode 100644 health/hdp_types.h
create mode 100644 health/hdp_util.c
create mode 100644 health/hdp_util.h
create mode 100644 health/main.c
create mode 100644 health/manager.c
create mode 100644 health/manager.h
diff --git a/Makefile.am b/Makefile.am
index f96d556..9be4865 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -169,6 +169,14 @@ builtin_modules += service
builtin_sources += plugins/service.c
endif
+if HEALTHPLUGIN
+builtin_modules += health
+builtin_sources += health/main.c \
+ health/manager.h health/manager.c \
+ health/hdp.h health/hdp.c \
+ health/hdp_util.h health/hdp_util.c
+endif
+
if MCAP
mcap_sources += mcap/mcap_internal.h \
mcap/mcap_lib.h mcap/sync.c \
diff --git a/acinclude.m4 b/acinclude.m4
index b512cfb..23c594a 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -167,6 +167,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
serial_enable=yes
network_enable=yes
service_enable=yes
+ health_enable=no
mcap_enable=no
pnat_enable=no
tracer_enable=no
@@ -216,6 +217,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
service_enable=${enableval}
])
+ AC_ARG_ENABLE(health, AC_HELP_STRING([--enable-health], [enable health plugin]), [
+ health_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(mcap, AC_HELP_STRING([--enable-mcap], [enable mcap support]), [
mcap_enable=${enableval}
])
@@ -330,7 +335,8 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
- AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes")
+ AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
+ AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes" || test "${health_enable}" = "yes")
AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
diff --git a/health/hdp.c b/health/hdp.c
new file mode 100644
index 0000000..2dec069
--- /dev/null
+++ b/health/hdp.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <gdbus.h>
+
+#include "log.h"
+#include "error.h"
+
+#include "hdp_types.h"
+#include "hdp_util.h"
+
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+
+#include "../src/dbus-common.h"
+
+static GSList *adapters = NULL;
+
+static struct hdp_adapter *find_adapter(GSList *list,
+ struct btd_adapter *btd_adapter)
+{
+ GSList *l;
+ struct hdp_adapter *adapter;
+
+ for (l = list; l; l = l->next) {
+ adapter = l->data;
+ if (adapter->btd_adapter == btd_adapter)
+ return adapter;
+ }
+
+ return NULL;
+}
+
+static void hdp_set_instance_id(struct hdp_instance *hdpi)
+{
+ struct hdp_adapter *adapter = hdpi->adapter;
+
+ hdpi->id = adapter->ic++;
+}
+
+static DBusMessage *hdp_create_instance(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_adapter *adapter = user_data;
+ const char *path, *name;
+ DBusMessageIter iter;
+ GError *err = NULL;
+ DBusMessage *reply;
+ struct hdp_instance *hdpi;
+ struct hdp_config *config;
+ int ctype;
+
+ dbus_message_iter_init(msg, &iter);
+ ctype = dbus_message_iter_get_arg_type(&iter);
+ if (ctype != DBUS_TYPE_OBJECT_PATH)
+ goto error;
+ dbus_message_iter_get_basic(&iter, &path);
+ dbus_message_iter_next(&iter);
+ config = hdp_get_config(&iter, &err);
+ if (err)
+ goto error;
+ name = dbus_message_get_sender(msg);
+ if (!name) {
+ g_set_error(&err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Can't get sender name");
+ goto error;
+ }
+
+ hdpi = g_new0(struct hdp_instance, 1);
+ hdpi->adapter = adapter;
+ hdpi->aname = g_strdup(name);
+ hdpi->apath = g_strdup(path);
+ hdpi->config = config;
+ if (!config->svc_dsc)
+ config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
+ if (!config->svc_name)
+ config->svc_name = g_strdup(HDP_SERVICE_NAME);
+ if (!config->svc_prov)
+ config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
+ hdp_set_instance_id(hdpi);
+
+ /* TODO: Create mcap instance */
+
+ /* TODO: Create SDP record if needed. */
+
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".HealthError",
+ "Incomplete call yet");
+error:
+ if (err) {
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments: %s", err->message);
+ g_error_free(err);
+ } else
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return reply;
+}
+
+static GDBusMethodTable hdp_methods[] = {
+ { "CreateInstance", "oa{sv}", "u", hdp_create_instance },
+ { NULL }
+};
+
+void hdp_delete_instance_iter(gpointer data, gpointer user_data)
+{
+ /* struct hdp_instance *hdpi = data; */
+
+ /* TODO: Create a free function */
+}
+
+static void hdp_path_unregister(void *data)
+{
+ struct hdp_adapter *adapter = data;
+
+ g_slist_foreach(adapter->instances, hdp_delete_instance_iter, NULL);
+ g_slist_free(adapter->instances);
+ adapter->instances = NULL;
+ DBG("All hdp instance for removed adapter were closed");
+}
+
+int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
+{
+ const char *path = adapter_get_path(btd_adapter);
+
+ struct hdp_adapter *adapter;
+ adapter = g_new0(struct hdp_adapter, 1);
+
+ DBG("HDP init");
+ if (!g_dbus_register_interface(conn, path, HEALTH_MANAGER_INTERFACE,
+ hdp_methods, NULL, NULL,
+ adapter, hdp_path_unregister)) {
+ error("Failed to register %s interface to %s",
+ HEALTH_MANAGER_INTERFACE, path);
+ g_free(adapter);
+ return -1;
+ }
+ adapter->conn = dbus_connection_ref(conn);
+ adapter->btd_adapter = btd_adapter_ref(btd_adapter);
+ adapters = g_slist_prepend(adapters, adapter);
+ return 0;
+}
+
+void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
+{
+ struct hdp_adapter *adapter;
+
+ adapter = find_adapter(adapters, btd_adapter);
+ if (!adapter)
+ return;
+
+ g_dbus_unregister_interface(adapter->conn,
+ adapter_get_path(btd_adapter),
+ HEALTH_MANAGER_INTERFACE);
+ dbus_connection_unref(adapter->conn);
+ btd_adapter_unref(adapter->btd_adapter);
+ adapters = g_slist_remove(adapters, adapter);
+ g_free(adapter);
+
+ DBG("HDP exit");
+}
diff --git a/health/hdp.h b/health/hdp.h
new file mode 100644
index 0000000..893f745
--- /dev/null
+++ b/health/hdp.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
+void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
diff --git a/health/hdp_types.h b/health/hdp_types.h
new file mode 100644
index 0000000..2db9adf
--- /dev/null
+++ b/health/hdp_types.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+
+#ifndef __HDP_TYPES_H__
+#define __HDP_TYPES_H__
+
+#include <glib.h>
+#include "mcap_lib.h"
+
+#define HDP_SERVICE_NAME "Bluez HDP"
+#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
+#define HDP_SERVICE_PROVIDER "Bluez"
+
+#define HDP_VERSION 0x0100
+
+#define HDP_ERROR g_quark_from_static_string("hdp-error-quark")
+
+typedef enum {
+ HDP_DIC_PARSE_ERROR,
+ HDP_DIC_ENTRY_PARSE_ERROR,
+ HDP_UNSPECIFIED_ERROR,
+ HDP_UNKNOWN_ERROR
+} HdpError;
+
+enum data_specs {
+ DATA_EXCHANGE_SPEC_11073 = 0x01
+};
+
+typedef enum {
+ HDP_SOURCE = 0x00,
+ HDP_SINK = 0x01
+} HdpRole;
+
+struct hdp_feature {
+ guint16 dtype; /* Data type (see 5.2.9.2) */
+ gboolean dtype_present; /* Data type present in config */
+ char *dscr; /* Displayable TextName */
+};
+
+struct hdp_supp_fts {
+ guint8 mdepid; /* (0x01-0x7F) Available for use */
+ HdpRole role; /* Role (see table 5.3) */
+ gboolean role_present; /* Role present in config */
+ GSList *features; /* Feature list */
+};
+
+struct hdp_config {
+ guint8 data_spec; /* Data exchange specification */
+ GSList *supp_fts; /* Supported features list */
+ char *svc_name; /* Service name to register in SDP */
+ char *svc_dsc; /* Service description */
+ char *svc_prov; /* Service provider */
+ gboolean ds_present; /* Data spec has been assigned */
+};
+
+struct hdp_adapter {
+ struct btd_adapter *btd_adapter;
+ DBusConnection *conn; /* DBus connection */
+ GSList *instances; /* HDP instances list */
+ uint16_t ic; /* Instances counter */
+};
+
+struct hdp_instance {
+ struct hdp_adapter *adapter; /* HDP adapter */
+ struct mcap_instance *mi; /* MCAP instance */
+ uint16_t ccpsm; /* Control channel psm */
+ uint16_t dcpsm; /* Data channel psm */
+ GSList *hlink; /* Health Links */
+ uint32_t id; /* HDP instance id */
+ char *apath; /* HDP agent path */
+ char *aname; /* HDP agent name */
+ struct hdp_config *config; /* Configuration */
+ uint32_t sdp_handler; /* SDP record handler */
+};
+
+#endif /* __HDP_TYPES_H__ */
diff --git a/health/hdp_util.c b/health/hdp_util.c
new file mode 100644
index 0000000..a215d5a
--- /dev/null
+++ b/health/hdp_util.c
@@ -0,0 +1,447 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gdbus.h>
+#include "log.h"
+#include "hdp_types.h"
+
+typedef gboolean (*parse_item_f)(DBusMessageIter *iter, GError **err,
+ gpointer user_data);
+
+struct dict_entry_func {
+ char *key;
+ parse_item_f func;
+};
+
+static gboolean check_feature(struct hdp_feature *feature)
+{
+ return feature->dtype_present;
+}
+
+static gboolean check_feature_list(struct hdp_supp_fts *fts)
+{
+ return fts->role_present && (fts->features != NULL);
+}
+
+static gboolean check_config(struct hdp_config *config)
+{
+ if (config->ds_present)
+ return config->supp_fts != NULL;
+ return TRUE;
+}
+
+static gboolean hdp_check_data_spec(guint8 data_spec)
+{
+ /* Future versions may edit this function
+ * If there are more supported data exchange specifications
+ */
+ return data_spec == DATA_EXCHANGE_SPEC_11073;
+}
+
+static void free_feature(struct hdp_feature *feature)
+{
+ if (feature->dscr) {
+ g_free(feature->dscr);
+ feature->dscr = NULL;
+ }
+ g_free(feature);
+}
+
+static void free_feature_list(struct hdp_supp_fts *fts)
+{
+ GSList *l;
+
+ for (l = fts->features; l; l = l->next)
+ free_feature(l->data);
+ g_slist_free(fts->features);
+ fts->features = NULL;
+ g_free(fts);
+}
+
+static void free_config(struct hdp_config *config)
+{
+ GSList *l;
+
+ for (l = config->supp_fts; l; l = l->next)
+ free_feature_list(l->data);
+ g_slist_free(config->supp_fts);
+ config->supp_fts = NULL;
+ if (config->svc_dsc) {
+ g_free(config->svc_dsc);
+ config->svc_dsc = NULL;
+ }
+ if (config->svc_name) {
+ g_free(config->svc_name);
+ config->svc_name = NULL;
+ }
+ if (config->svc_prov) {
+ g_free(config->svc_prov);
+ config->svc_prov = NULL;
+ }
+ g_free(config);
+}
+
+static gboolean parse_dict_entry(struct dict_entry_func dict_context[],
+ DBusMessageIter *iter,
+ GError **err,
+ gpointer user_data)
+{
+ DBusMessageIter entry;
+ char *key;
+ int ctype, i;
+ struct dict_entry_func df;
+
+ dbus_message_iter_recurse(iter, &entry);
+ ctype = dbus_message_iter_get_arg_type(&entry);
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Dictionary entries should have a string as key");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ /* Find function and call it */
+ for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) {
+ if (g_strcmp0(df.key, key) == 0) {
+ return df.func(&entry, err, user_data);
+ }
+ }
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "No function found for parsing value for key %s", key);
+ return FALSE;
+}
+
+static gboolean parse_dict(struct dict_entry_func dict_context[],
+ DBusMessageIter *iter,
+ GError **err,
+ gpointer user_data)
+{
+ int ctype;
+ DBusMessageIter dict;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary should be an array");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID) {
+ if (ctype != DBUS_TYPE_DICT_ENTRY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary array should "
+ "contain dict entries");
+ return FALSE;
+ }
+ /* Start parsing entry */
+ if (!parse_dict_entry(dict_context, &dict, err,
+ user_data))
+ return FALSE;
+ /* Finish entry parsing */
+ dbus_message_iter_next(&dict);
+ }
+ return TRUE;
+}
+
+static gboolean parse_description(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_feature *feat = data;
+ DBusMessageIter *string, variant;
+ int ctype;
+ const char *desc;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ string = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &variant);
+ ctype = dbus_message_iter_get_arg_type(&variant);
+ string = &variant;
+ }
+
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Value data spec should be variable or string");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(string, &desc);
+ feat->dscr = g_strdup(desc);
+ return TRUE;
+}
+
+static gboolean parse_data_type(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_feature *feat = data;
+ DBusMessageIter *value, variant;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ value = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &variant);
+ ctype = dbus_message_iter_get_arg_type(&variant);
+ value = &variant;
+ }
+
+ if (ctype != DBUS_TYPE_UINT16) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Final value for data type should be a uint16");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(value, &feat->dtype);
+
+ /*
+ * This data should be check by the application layer because it
+ * depends on the data_spec values and is specific for each value
+ */
+ feat->dtype_present = TRUE;
+
+ return TRUE;
+}
+
+static struct dict_entry_func specs_context[] = {
+ {"data_type", parse_data_type},
+ {"description", parse_description},
+ {NULL, NULL}
+};
+
+static gboolean parse_specs(DBusMessageIter *iter, GError **err, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ struct hdp_feature *feature = NULL;
+ DBusMessageIter *array, value, dict;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ array = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ array = &value;
+ }
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Value specs should be variable or array");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(array, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID){
+ feature = g_new0(struct hdp_feature, 1);
+ if (!parse_dict(specs_context, &dict, err, feature))
+ goto error;
+ if (!check_feature(feature)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Field \"data_type\" is mandatory");
+ goto error;
+ }
+ fts->features = g_slist_append(fts->features, feature);
+ dbus_message_iter_next(&dict);
+ }
+
+ return TRUE;
+error:
+ if (feature)
+ free_feature(feature);
+ return FALSE;
+}
+
+static gboolean parse_role(DBusMessageIter *iter, GError **err, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ DBusMessageIter value;
+ DBusMessageIter *string;
+ int ctype;
+ const char *role;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ string = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ string = &value;
+ }
+
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value data spec should be variable or string");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(string, &role);
+ if (g_strcmp0(role, "sink") == 0)
+ fts->role = HDP_SINK;
+ else if (g_strcmp0(role, "source") == 0)
+ fts->role = HDP_SOURCE;
+ else {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Role value should be \"source\" or \"sink\"");
+ return FALSE;
+ }
+ fts->role_present = TRUE;
+ return TRUE;
+}
+
+static struct dict_entry_func end_point_context[] = {
+ {"role", parse_role},
+ {"specs", parse_specs},
+ {NULL, NULL}
+};
+
+static gboolean parse_end_points(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_config *config = data;
+ struct hdp_supp_fts *fts = NULL;
+ DBusMessageIter array, dict;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_VARIANT) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value for end points should be variable");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &array);
+ ctype = dbus_message_iter_get_arg_type(&array);
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value end_point should be array inside variable");
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse(&array, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID){
+
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary should be an array");
+ return FALSE;
+ }
+ fts = g_new0(struct hdp_supp_fts, 1);
+ if (!parse_dict(end_point_context, &dict, err, fts))
+ goto error;
+ if (!check_feature_list(fts)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Role field and specs are mandatory");
+ goto error;
+ }
+ config->supp_fts = g_slist_append(config->supp_fts, fts);
+ dbus_message_iter_next(&dict);
+ }
+ return TRUE;
+error:
+ if (fts)
+ free_feature_list(fts);
+ return FALSE;
+}
+
+static gboolean parse_data_spec(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_config *config = data;
+ DBusMessageIter value;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_VARIANT) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value data spec should be variable");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ if (ctype != DBUS_TYPE_BYTE) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Final value data spec should be byte");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(&value, &config->data_spec);
+
+ if (!hdp_check_data_spec(config->data_spec))
+ return FALSE;
+ config->ds_present = TRUE;
+ return TRUE;
+}
+
+static struct dict_entry_func main_context[] = {
+ {"data_spec", parse_data_spec},
+ {"end_points", parse_end_points},
+ {NULL, NULL}
+};
+
+static void print_feature(gpointer elem, gpointer data)
+{
+ struct hdp_feature *feat = elem;
+
+ DBG(" Feature:");
+ DBG(" description: %s", feat->dscr);
+ DBG(" data type: %u", feat->dtype);
+}
+
+static void print_features(gpointer elem, gpointer data)
+{
+ struct hdp_supp_fts *fts = elem;
+
+ DBG("Mdep:");
+ DBG(" mdepid %u", fts->mdepid);
+ DBG(" role %d", fts->role);
+ g_slist_foreach(fts->features, print_feature, NULL);
+}
+
+struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err)
+{
+ struct hdp_config *config;
+
+ config = g_new0(struct hdp_config, 1);
+
+ if (!parse_dict(main_context, iter, err, config))
+ goto error;
+
+ /* TODO check config */
+ if (!check_config(config)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "\"data_spec\" and \"end_point\" should be set or not");
+ goto error;
+ }
+ if (!config->ds_present)
+ goto error;
+ DBG("config->data_spec %d", config->data_spec);
+ g_slist_foreach(config->supp_fts, print_features, NULL);
+ return config;
+error:
+ if (config)
+ free_config(config);
+ return NULL;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
new file mode 100644
index 0000000..f09e9a6
--- /dev/null
+++ b/health/hdp_util.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __HDP_UTIL_H__
+#define __HDP_UTIL_H__
+
+#include <gdbus.h>
+#include "hdp_types.h"
+
+struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
+
+#endif /* __HDP_UTIL_H__ */
diff --git a/health/main.c b/health/main.c
new file mode 100644
index 0000000..6ece69b
--- /dev/null
+++ b/health/main.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int hdp_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (hdp_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void hdp_exit(void)
+{
+ hdp_manager_exit();
+
+ dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(health, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, hdp_init, hdp_exit)
diff --git a/health/manager.c b/health/manager.c
new file mode 100644
index 0000000..dc354f8
--- /dev/null
+++ b/health/manager.c
@@ -0,0 +1,101 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "device.h"
+
+#include "log.h"
+#include "manager.h"
+#include "hdp.h"
+
+#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
+#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
+#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+
+static DBusConnection *connection = NULL;
+
+static int hdp_adapter_probe(struct btd_adapter *adapter)
+{
+ return hdp_adapter_register(connection, adapter);
+}
+
+static void hdp_adapter_remove(struct btd_adapter *adapter)
+{
+ hdp_adapter_unregister(adapter);
+}
+
+static struct btd_adapter_driver hdp_adapter_driver = {
+ .name = "hdp-adapter-driver",
+ .probe = hdp_adapter_probe,
+ .remove = hdp_adapter_remove,
+};
+
+static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ DBG("hdp driver probe");
+ return 0;
+}
+
+static void hdp_driver_remove(struct btd_device *device)
+{
+ DBG("hdp driver remove");
+}
+
+static struct btd_device_driver hdp_device_driver = {
+ .name = "hdp_device-driver",
+ .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
+ .probe = hdp_driver_probe,
+ .remove = hdp_driver_remove,
+};
+
+int hdp_manager_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+
+ btd_register_adapter_driver(&hdp_adapter_driver);
+ btd_register_device_driver(&hdp_device_driver);
+
+ DBG("hdp manager init");
+ return 0;
+}
+
+void hdp_manager_exit(void)
+{
+ btd_unregister_device_driver(&hdp_device_driver);
+ btd_unregister_adapter_driver(&hdp_adapter_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+ DBG("hdp manager exit");
+}
diff --git a/health/manager.h b/health/manager.h
new file mode 100644
index 0000000..b91ef75
--- /dev/null
+++ b/health/manager.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int hdp_manager_init(DBusConnection *conn);
+void hdp_manager_exit(void);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 03/32] Add functions to resiger health instances in SDP
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-3-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 5 +-
health/hdp_util.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++++
health/hdp_util.h | 1 +
3 files changed, 398 insertions(+), 1 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 2dec069..454483d 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -101,7 +101,10 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
/* TODO: Create mcap instance */
- /* TODO: Create SDP record if needed. */
+ if (!hdp_register_sdp_record(hdpi)) {
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Session can't be registered");
+ }
return g_dbus_create_error(msg,
ERROR_INTERFACE ".HealthError",
diff --git a/health/hdp_util.c b/health/hdp_util.c
index a215d5a..cc5dc2e 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -24,8 +24,14 @@
*/
#include <gdbus.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include "log.h"
+#include "sdpd.h"
+
#include "hdp_types.h"
+#include "hdp_util.h"
+#include "mcap.h"
typedef gboolean (*parse_item_f)(DBusMessageIter *iter, GError **err,
gpointer user_data);
@@ -445,3 +451,390 @@ error:
free_config(config);
return NULL;
}
+
+static gboolean is_session_role(struct hdp_instance *hdps, HdpRole role)
+{
+ GSList *l;
+ struct hdp_supp_fts *fts;
+
+ if (!hdps->config)
+ return FALSE;
+ for (l = hdps->config->supp_fts; l; l = l->next) {
+ fts = l->data;
+ if (fts->role == role)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean register_service_protocols(struct hdp_instance *hdps,
+ sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ uuid_t l2cap_uuid, mcap_c_uuid;
+ sdp_list_t *l2cap_list = NULL,
+ *proto_list = NULL,
+ *mcap_list = NULL,
+ *access_proto_list = NULL;
+ sdp_data_t *psm = NULL,
+ *mcap_ver = NULL;
+ uint16_t version = MCAP_VERSION;
+
+ // set l2cap information
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list) {
+ error = TRUE;
+ goto end;
+ }
+ psm = sdp_data_alloc(SDP_UINT16, &hdps->ccpsm);
+ if (!psm) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append(l2cap_list, psm)) {
+ error = TRUE;
+ goto end;
+ }
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list) {
+ error = TRUE;
+ goto end;
+ }
+
+ // set mcap information
+ sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_c_uuid);
+ if (!mcap_list) {
+ error = TRUE;
+ goto end;
+ }
+ mcap_ver = sdp_data_alloc(SDP_UINT16, &version);
+ if (!mcap_ver) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( mcap_list, mcap_ver)) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( proto_list, mcap_list)) {
+ error = TRUE;
+ goto end;
+ }
+
+ // attach protocol information to service record
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (sdp_set_access_protos(sdp_record, access_proto_list) < 0)
+ error = TRUE;
+end:
+ if (l2cap_list)
+ sdp_list_free(l2cap_list, NULL);
+ if (mcap_list)
+ sdp_list_free(mcap_list, NULL);
+ if (proto_list)
+ sdp_list_free(proto_list, NULL);
+ if (access_proto_list)
+ sdp_list_free(access_proto_list, NULL);
+ if (psm)
+ sdp_data_free(psm);
+ if (mcap_ver)
+ sdp_data_free(mcap_ver);
+ return !error;
+}
+
+static gboolean register_service_profiles(sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ sdp_list_t *profile_list = NULL;
+ sdp_profile_desc_t hdp_profile;
+
+ // set hdp information
+ sdp_uuid16_create( &hdp_profile.uuid, MDP_SVCLASS_ID);
+ hdp_profile.version = HDP_VERSION;
+ profile_list = sdp_list_append(NULL, &hdp_profile);
+ if (!profile_list)
+ return FALSE;
+ // set profile descriptor list
+ if (sdp_set_profile_descs(sdp_record, profile_list) < 0)
+ error = TRUE;
+
+ sdp_list_free(profile_list, NULL);
+ return !error;
+}
+
+static gboolean register_service_aditional_protocols(struct hdp_instance *hdps,
+ sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ uuid_t l2cap_uuid, mcap_d_uuid;
+ sdp_list_t *l2cap_list = NULL,
+ *proto_list = NULL,
+ *mcap_list = NULL,
+ *access_proto_list = NULL;
+ sdp_data_t *psm = NULL;
+
+ // set l2cap information
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list) {
+ error = TRUE;
+ goto end;
+ }
+ psm = sdp_data_alloc(SDP_UINT16, &hdps->dcpsm);
+ if (!psm) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append(l2cap_list, psm)) {
+ error = TRUE;
+ goto end;
+ }
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list) {
+ error = TRUE;
+ goto end;
+ }
+
+ // set mcap information
+ sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_d_uuid);
+ if (!mcap_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( proto_list, mcap_list)) {
+ error = TRUE;
+ goto end;
+ }
+
+ // attach protocol information to service record
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0)
+ error = TRUE;
+end:
+ if (l2cap_list)
+ sdp_list_free(l2cap_list, NULL);
+ if (mcap_list)
+ sdp_list_free(mcap_list, NULL);
+ if (proto_list)
+ sdp_list_free(proto_list, NULL);
+ if (access_proto_list)
+ sdp_list_free(access_proto_list, NULL);
+ if (psm)
+ sdp_data_free(psm);
+ return !error;
+}
+
+static sdp_list_t *feature_to_sdplist(struct hdp_supp_fts *fts,
+ struct hdp_feature *f)
+{
+ sdp_data_t *mdepid,
+ *dtype = NULL,
+ *role = NULL,
+ *desc = NULL;
+ sdp_list_t *f_list = NULL;
+
+ mdepid = sdp_data_alloc(SDP_UINT8, &fts->mdepid);
+ if (!mdepid)
+ return NULL;
+ dtype = sdp_data_alloc(SDP_UINT16, &f->dtype);
+ if (!dtype)
+ goto error;
+ role = sdp_data_alloc(SDP_UINT8, &fts->role);
+ if (!role)
+ goto error;
+ if (f->dscr) {
+ desc = sdp_data_alloc(SDP_TEXT_STR8, f->dscr);
+ if (!desc)
+ goto error;
+ }
+ f_list = sdp_list_append(NULL, mdepid);
+ if (!f_list)
+ goto error;
+ if (!sdp_list_append(f_list, dtype))
+ goto error;
+ if (!sdp_list_append(f_list, role))
+ goto error;
+ if (desc)
+ if (!sdp_list_append(f_list, desc))
+ goto error;
+ return f_list;
+error:
+ if (f_list)
+ sdp_list_free(f_list, NULL);
+ if (mdepid)
+ sdp_data_free(mdepid);
+ if (dtype)
+ sdp_data_free(dtype);
+ if (role)
+ sdp_data_free(role);
+ if (desc)
+ sdp_data_free(desc);
+ return NULL;
+}
+
+static gboolean register_features(struct hdp_supp_fts *fts,
+ sdp_list_t **sup_features)
+{
+ GSList *l;
+ sdp_list_t *hdp_feature = NULL;
+
+ for (l = fts->features; l; l = l->next){
+ hdp_feature = feature_to_sdplist(fts, l->data);
+ if (!hdp_feature)
+ goto error;
+
+ if (!*sup_features) {
+ *sup_features = sdp_list_append(NULL, hdp_feature);
+ if (!*sup_features)
+ goto error;
+ } else if (!sdp_list_append(*sup_features, hdp_feature))
+ goto error;
+ hdp_feature = NULL;
+ }
+ return TRUE;
+error:
+ if (hdp_feature)
+ sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free);
+ return FALSE;
+}
+
+static void free_hdp_list(void *list)
+{
+ sdp_list_t *hdp_list = list;
+
+ sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free);
+}
+
+static gboolean register_service_sup_features(struct hdp_config *config,
+ sdp_record_t *sdp_record)
+{
+ GSList *l;
+ sdp_list_t *sup_features = NULL;
+ for (l = config->supp_fts; l; l = l->next) {
+ if (!register_features(l->data, &sup_features))
+ return FALSE;
+ }
+ if (sdp_set_supp_feat(sdp_record, sup_features) < 0) {
+ sdp_list_free(sup_features, free_hdp_list);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean register_data_exchange_spec(struct hdp_config *config,
+ sdp_record_t *record)
+{
+ sdp_data_t *spec;
+
+ spec = sdp_data_alloc(SDP_UINT8, &config->data_spec);
+ if (!spec)
+ return FALSE;
+ if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) {
+ sdp_data_free(spec);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean register_mcap_features(sdp_record_t *sdp_record)
+{
+ sdp_data_t *mcap_proc;
+ uint8_t mcap_sup_proc = MCAP_SUP_PROC;
+
+ mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc);
+ if (!mcap_proc)
+ return FALSE;
+ if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES,
+ mcap_proc) < 0) {
+ sdp_data_free(mcap_proc);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role)
+{
+ uuid_t svc_uuid_source, svc_uuid_sink;
+ sdp_list_t *svc_list = NULL;
+
+ sdp_uuid16_create(&svc_uuid_sink, MDP_SINK_SVCLASS_ID);
+ sdp_uuid16_create(&svc_uuid_source, MDP_SOURCE_SVCLASS_ID);
+
+ sdp_get_service_classes(record, &svc_list);
+
+ if (role == HDP_SOURCE) {
+ if (sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp) == NULL)
+ svc_list = sdp_list_append(svc_list, &svc_uuid_source);
+ }
+ else if (role == HDP_SINK) {
+ if (sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp) == NULL)
+ svc_list = sdp_list_append(svc_list, &svc_uuid_sink);
+ }
+
+ if (sdp_set_service_classes(record, svc_list) < 0) {
+ sdp_list_free(svc_list, NULL);
+ return FALSE;
+ }
+
+ sdp_list_free(svc_list, NULL);
+ return TRUE;
+}
+
+gboolean hdp_register_sdp_record(struct hdp_instance *hdps)
+{
+ sdp_record_t *sdp_record;
+ struct hdp_config *config;
+ bdaddr_t addr;
+
+ if (!hdps->config) /* Record is not needed */
+ return TRUE;
+ config = hdps->config;
+
+ sdp_record = sdp_record_alloc();
+ if (!sdp_record)
+ return FALSE;
+ sdp_record->handle = 0xffffffff; /* Set automatically */
+
+ if (is_session_role(hdps, HDP_SINK))
+ set_sdp_services_uuid(sdp_record, HDP_SINK);
+ if (is_session_role(hdps, HDP_SOURCE))
+ set_sdp_services_uuid(sdp_record, HDP_SOURCE);
+
+ if (!register_service_protocols(hdps, sdp_record))
+ goto error;
+ if (!register_service_profiles(sdp_record))
+ goto error;
+ if (!register_service_aditional_protocols(hdps, sdp_record))
+ goto error;
+ sdp_set_info_attr(sdp_record, config->svc_name, config->svc_prov,
+ config->svc_dsc);
+ if (!register_service_sup_features(config, sdp_record))
+ goto error;
+ if (!register_data_exchange_spec(config, sdp_record))
+ goto error;
+
+ register_mcap_features(sdp_record);
+
+ adapter_get_address(hdps->adapter->btd_adapter, &addr);
+
+ if (add_record_to_server(&addr, sdp_record) < 0)
+ goto error;
+ hdps->sdp_handler = sdp_record->handle;
+ return TRUE;
+error:
+ if (sdp_record)
+ sdp_record_free(sdp_record);
+ return FALSE;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index f09e9a6..fb114c7 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -30,5 +30,6 @@
#include "hdp_types.h"
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
+gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 04/32] Initial support for hdp_device_drivers
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: José Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-4-git-send-email-santoscadenas@gmail.com>
From: José Antonio Santos Cadenas <santoscadenas@gmail.com>
---
health/hdp.c | 11 +++++++++++
health/hdp.h | 3 +++
health/manager.c | 10 +++++++---
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 454483d..dbe326e 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -184,3 +184,14 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
DBG("HDP exit");
}
+
+int health_device_register(struct btd_device *device, const char *uuid)
+{
+ DBG("HDP_DRIVER_PROBE with uuid %s", uuid);
+ return 0;
+}
+
+void health_device_unregister(struct btd_device *device)
+{
+ DBG("TODO: Remove device");
+}
diff --git a/health/hdp.h b/health/hdp.h
index 893f745..0aae7b9 100644
--- a/health/hdp.h
+++ b/health/hdp.h
@@ -25,3 +25,6 @@
int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
+
+int health_device_register(struct btd_device *device, const char *uuid);
+void health_device_unregister(struct btd_device *device);
diff --git a/health/manager.c b/health/manager.c
index dc354f8..d163545 100644
--- a/health/manager.c
+++ b/health/manager.c
@@ -63,17 +63,21 @@ static struct btd_adapter_driver hdp_adapter_driver = {
static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
{
- DBG("hdp driver probe");
+ while (uuids) {
+ health_device_register(device, uuids->data);
+ uuids = uuids->next;
+ }
+
return 0;
}
static void hdp_driver_remove(struct btd_device *device)
{
- DBG("hdp driver remove");
+ health_device_unregister(device);
}
static struct btd_device_driver hdp_device_driver = {
- .name = "hdp_device-driver",
+ .name = "hdp-device-driver",
.uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
.probe = hdp_driver_probe,
.remove = hdp_driver_remove,
--
1.6.3.3
^ permalink raw reply related
* [PATCH 05/32] Register healt_driver interfaces in d-bus
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: José Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-5-git-send-email-santoscadenas@gmail.com>
From: José Antonio Santos Cadenas <santoscadenas@gmail.com>
Register interface for each hdp_driver plugged
Unregister driver
Device_get_health_instances method added
Add function to get data exchange spec from a remote record
---
health/hdp.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++---
health/hdp.h | 4 +-
health/hdp_types.h | 10 ++++
health/hdp_util.c | 11 +++++
health/hdp_util.h | 2 +
health/manager.c | 20 +++-----
6 files changed, 151 insertions(+), 22 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index dbe326e..5b09ab3 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -29,12 +29,16 @@
#include "hdp_types.h"
#include "hdp_util.h"
-
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#include "device.h"
#include "../src/dbus-common.h"
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#define HEALTH_INSTANCE_INTERFACE "org.bluez.HealthInstance"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+
static GSList *adapters = NULL;
+static GSList *devices = NULL;
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
@@ -51,6 +55,98 @@ static struct hdp_adapter *find_adapter(GSList *list,
return NULL;
}
+static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
+{
+ GSList *l;
+ struct hdp_device *device;
+
+ for (l = devices; l != NULL; l = l->next) {
+ device = l->data;
+
+ if (device->dev == dev)
+ return device;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *get_health_instances(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ const sdp_record_t *rec;
+ guint8 data_spec;
+
+ rec = btd_device_get_record(device->dev, HDP_UUID);
+
+ if (!rec) {
+ DBG("No record found");
+ goto error;
+ }
+
+ if (!hdp_get_data_exchange_spec(rec, &data_spec))
+ goto error;
+
+ DBG("Get data exchange spec %d", data_spec);
+error:
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Cannot get the remote SDP record");
+}
+
+static void health_device_free(struct hdp_device *device)
+{
+ if (device->conn) {
+ dbus_connection_unref(device->conn);
+ device->conn = NULL;
+ }
+
+ if (device->dev) {
+ btd_device_unref(device->dev);
+ device->dev = NULL;
+ }
+
+ g_free(device);
+}
+
+static void dev_path_unregister(void *data)
+{
+ struct hdp_device *device = data;
+
+
+ DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
+ device_get_path(device->dev));
+ devices = g_slist_remove(devices, device);
+ health_device_free(device);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetHealthInstances", "", "a{sv}", get_health_instances },
+ { NULL }
+};
+
+static struct hdp_device *create_health_device(DBusConnection *conn,
+ struct btd_device *device)
+{
+ const gchar *path = device_get_path(device);
+ struct hdp_device *dev;
+
+ dev = g_new0(struct hdp_device, 1);
+ dev->conn = dbus_connection_ref(conn);
+ dev->dev = btd_device_ref(device);
+
+ if (!g_dbus_register_interface(conn, path,
+ HEALTH_DEVICE,
+ device_methods, NULL, NULL,
+ dev, dev_path_unregister)) {
+ error("D-Bus failed to register %s interface", HEALTH_DEVICE);
+ health_device_free(dev);
+ return NULL;
+ }
+
+ DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
+ return dev;
+}
+
static void hdp_set_instance_id(struct hdp_instance *hdpi)
{
struct hdp_adapter *adapter = hdpi->adapter;
@@ -59,7 +155,7 @@ static void hdp_set_instance_id(struct hdp_instance *hdpi)
}
static DBusMessage *hdp_create_instance(DBusConnection *conn,
- DBusMessage *msg, void *user_data)
+ DBusMessage *msg, void *user_data)
{
struct hdp_adapter *adapter = user_data;
const char *path, *name;
@@ -185,13 +281,29 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
DBG("HDP exit");
}
-int health_device_register(struct btd_device *device, const char *uuid)
+int hdp_device_register(DBusConnection *conn, struct btd_device *device)
{
- DBG("HDP_DRIVER_PROBE with uuid %s", uuid);
+ struct hdp_device *hdp_dev;
+
+ hdp_dev = find_device(devices, device);
+ if (!hdp_dev) {
+ hdp_dev = create_health_device(conn, device);
+ if (!hdp_dev)
+ return -1;
+ devices = g_slist_append(devices, hdp_dev);
+ }
return 0;
}
-void health_device_unregister(struct btd_device *device)
+void hdp_device_unregister(struct btd_device *device)
{
- DBG("TODO: Remove device");
+ struct hdp_device *hdp_dev;
+ const char *path;
+
+ hdp_dev = find_device(devices, device);
+ if (!hdp_dev)
+ return;
+
+ path = device_get_path(hdp_dev->dev);
+ g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
}
diff --git a/health/hdp.h b/health/hdp.h
index 0aae7b9..edb06a0 100644
--- a/health/hdp.h
+++ b/health/hdp.h
@@ -26,5 +26,5 @@
int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
-int health_device_register(struct btd_device *device, const char *uuid);
-void health_device_unregister(struct btd_device *device);
+int hdp_device_register(DBusConnection *conn, struct btd_device *device);
+void hdp_device_unregister(struct btd_device *device);
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 2db9adf..171910a 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -30,6 +30,10 @@
#include <glib.h>
#include "mcap_lib.h"
+#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
+#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
+#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+
#define HDP_SERVICE_NAME "Bluez HDP"
#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
#define HDP_SERVICE_PROVIDER "Bluez"
@@ -96,4 +100,10 @@ struct hdp_instance {
uint32_t sdp_handler; /* SDP record handler */
};
+struct hdp_device {
+ DBusConnection *conn; /* for name listener handling */
+ struct btd_device *dev; /* Device reference */
+ struct hdp_adapter *hdp_adapter; /* hdp_adapater */
+};
+
#endif /* __HDP_TYPES_H__ */
diff --git a/health/hdp_util.c b/health/hdp_util.c
index cc5dc2e..96fa737 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -838,3 +838,14 @@ error:
sdp_record_free(sdp_record);
return FALSE;
}
+
+gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
+{
+ sdp_data_t *exspec;
+
+ exspec = sdp_data_get(rec, SDP_ATTR_DATA_EXCHANGE_SPEC);
+ if (exspec->dtd != SDP_UINT8)
+ return FALSE;
+ *val = exspec->val.uint8;
+ return TRUE;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index fb114c7..0fdaaec 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -31,5 +31,7 @@
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
+gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+void hdp_instance_free(struct hdp_instance *hdpi);
#endif /* __HDP_UTIL_H__ */
diff --git a/health/manager.c b/health/manager.c
index d163545..8b52e93 100644
--- a/health/manager.c
+++ b/health/manager.c
@@ -28,20 +28,19 @@
#endif
#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include <glib.h>
#include <gdbus.h>
-#include "adapter.h"
-#include "device.h"
+#include "hdp_types.h"
#include "log.h"
#include "manager.h"
#include "hdp.h"
-#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
-#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
-#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+#include "device.h"
+#include "glib-helper.h"
static DBusConnection *connection = NULL;
@@ -63,22 +62,17 @@ static struct btd_adapter_driver hdp_adapter_driver = {
static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
{
- while (uuids) {
- health_device_register(device, uuids->data);
- uuids = uuids->next;
- }
-
- return 0;
+ return hdp_device_register(connection, device);
}
static void hdp_driver_remove(struct btd_device *device)
{
- health_device_unregister(device);
+ hdp_device_unregister(device);
}
static struct btd_device_driver hdp_device_driver = {
.name = "hdp-device-driver",
- .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
+ .uuids = BTD_UUIDS(HDP_UUID),
.probe = hdp_driver_probe,
.remove = hdp_driver_remove,
};
--
1.6.3.3
^ permalink raw reply related
* [PATCH 06/32] Add delete instance petition
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-6-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------
health/hdp_util.c | 35 +++++++++++++++++++++++++++-
2 files changed, 85 insertions(+), 14 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 5b09ab3..8d90588 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -34,7 +34,6 @@
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_INSTANCE_INTERFACE "org.bluez.HealthInstance"
#define HEALTH_DEVICE "org.bluez.HealthDevice"
static GSList *adapters = NULL;
@@ -147,6 +146,16 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
return dev;
}
+static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
+{
+ const struct hdp_instance *hdpi = instance;
+ const uint32_t *id = p;
+
+ if (hdpi->id == *id)
+ return 0;
+ return -1;
+}
+
static void hdp_set_instance_id(struct hdp_instance *hdpi)
{
struct hdp_adapter *adapter = hdpi->adapter;
@@ -187,24 +196,20 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->aname = g_strdup(name);
hdpi->apath = g_strdup(path);
hdpi->config = config;
- if (!config->svc_dsc)
- config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
- if (!config->svc_name)
- config->svc_name = g_strdup(HDP_SERVICE_NAME);
- if (!config->svc_prov)
- config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
hdp_set_instance_id(hdpi);
/* TODO: Create mcap instance */
if (!hdp_register_sdp_record(hdpi)) {
+ hdp_instance_free(hdpi);
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Session can't be registered");
}
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".HealthError",
- "Incomplete call yet");
+ adapter->instances = g_slist_prepend(adapter->instances, hdpi);
+ info("HDP instance created with path %d", hdpi->id);
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &hdpi->id,
+ DBUS_TYPE_INVALID);
error:
if (err) {
reply = g_dbus_create_error(msg,
@@ -218,16 +223,51 @@ error:
return reply;
}
+static DBusMessage *hdp_delete_instance(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_adapter *adapter = user_data;
+ struct hdp_instance *hdpi;
+ GSList *l;
+ const char *name;
+ uint32_t id;
+
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_INVALID))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+
+ l = g_slist_find_custom(adapter->instances, &id, hdp_instance_idcmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotFound",
+ "The session was not found");
+
+ name = dbus_message_get_sender(msg);
+ hdpi = l->data;
+ if (g_strcmp0(hdpi->aname, name) != 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "This session was created by an other process");
+ adapter->instances = g_slist_remove(adapter->instances, hdpi);
+ hdp_instance_free(hdpi);
+
+ DBG("Stop HDP Session %d deleted", id);
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
static GDBusMethodTable hdp_methods[] = {
{ "CreateInstance", "oa{sv}", "u", hdp_create_instance },
+ { "DeleteInstance", "u", "", hdp_delete_instance },
{ NULL }
};
void hdp_delete_instance_iter(gpointer data, gpointer user_data)
{
- /* struct hdp_instance *hdpi = data; */
+ struct hdp_instance *hdpi = data;
- /* TODO: Create a free function */
+ hdp_instance_free(hdpi);
}
static void hdp_path_unregister(void *data)
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 96fa737..31a0248 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -109,6 +109,28 @@ static void free_config(struct hdp_config *config)
g_free(config);
}
+void hdp_instance_free(struct hdp_instance *hdpi)
+{
+ DBG("HDP instance %d is deleted", hdpi->id);
+ /* TODO: Complete this part */
+ /*
+ g_slist_foreach(hdpi->devices, hdp_device_unregister, NULL);
+ g_slist_free(hdpi->devices);
+ hdpi->devices = NULL;
+ */
+
+ if (hdpi->sdp_handler)
+ remove_record_from_server(hdpi->sdp_handler);
+ /* TODO: stop mcap instance */
+ if (hdpi->apath)
+ g_free(hdpi->apath);
+ if (hdpi->aname)
+ g_free(hdpi->aname);
+ if (hdpi->config)
+ free_config(hdpi->config);
+ g_free(hdpi);
+}
+
static gboolean parse_dict_entry(struct dict_entry_func dict_context[],
DBusMessageIter *iter,
GError **err,
@@ -441,8 +463,17 @@ struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err)
"\"data_spec\" and \"end_point\" should be set or not");
goto error;
}
- if (!config->ds_present)
- goto error;
+ if (!config->ds_present) {
+ g_free(config);
+ return NULL;
+ }
+ if (!config->svc_dsc)
+ config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
+ if (!config->svc_name)
+ config->svc_name = g_strdup(HDP_SERVICE_NAME);
+ if (!config->svc_prov)
+ config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
+
DBG("config->data_spec %d", config->data_spec);
g_slist_foreach(config->supp_fts, print_features, NULL);
return config;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 07/32] Add watcher to control client disconections to delete hdp instance
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-7-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 11 +++++++++++
health/hdp_types.h | 1 +
health/hdp_util.c | 2 ++
3 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 8d90588..31abb4c 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -163,6 +163,15 @@ static void hdp_set_instance_id(struct hdp_instance *hdpi)
hdpi->id = adapter->ic++;
}
+static void client_disconnected(DBusConnection *connection, void *user_data)
+{
+ struct hdp_instance *hdpi = user_data;
+ struct hdp_adapter *adapter = hdpi->adapter;
+ DBG("Client disconnected from the bus, deleting hdp instance");
+ adapter->instances = g_slist_remove(adapter->instances, hdpi);
+ hdp_instance_free(hdpi);
+}
+
static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -197,6 +206,8 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->apath = g_strdup(path);
hdpi->config = config;
hdp_set_instance_id(hdpi);
+ hdpi->dbus_watcher = g_dbus_add_disconnect_watch(adapter->conn, name,
+ client_disconnected, hdpi, NULL);
/* TODO: Create mcap instance */
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 171910a..3bab4ea 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -98,6 +98,7 @@ struct hdp_instance {
char *aname; /* HDP agent name */
struct hdp_config *config; /* Configuration */
uint32_t sdp_handler; /* SDP record handler */
+ guint dbus_watcher; /* Client D-Bus conn watcher */
};
struct hdp_device {
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 31a0248..5397f11 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -119,6 +119,8 @@ void hdp_instance_free(struct hdp_instance *hdpi)
hdpi->devices = NULL;
*/
+ if (hdpi->dbus_watcher)
+ g_dbus_remove_watch(hdpi->adapter->conn, hdpi->dbus_watcher);
if (hdpi->sdp_handler)
remove_record_from_server(hdpi->sdp_handler);
/* TODO: stop mcap instance */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 08/32] Work in getting remote SDP records
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-8-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++--------
health/hdp_util.c | 5 +++
health/hdp_util.h | 1 +
3 files changed, 73 insertions(+), 13 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 31abb4c..4fb9d62 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -31,6 +31,8 @@
#include "hdp_util.h"
#include "device.h"
+#include "glib-helper.h"
+
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
@@ -39,6 +41,11 @@
static GSList *adapters = NULL;
static GSList *devices = NULL;
+struct instances_aux {
+ struct hdp_device *device;
+ DBusMessage *msg;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -69,27 +76,73 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct instances_aux *cb_data = user_data;
+ DBusMessage *msg = cb_data->msg;
+ struct hdp_device *device = cb_data->device;
+ DBusMessage *reply;
+ sdp_record_t *rec;
+ sdp_list_t *l;
+ guint8 data_spec;
+ GSList *end_points;
+
+ g_free(cb_data);
+
+ if (err != 0) {
+ error("Error getting sink records");
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ g_dbus_send_message(device->conn, reply);
+ return;
+ }
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ DBG("Record found 0x%x", rec->handle);
+ /* TODO: Check record */
+ if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
+ error("Error getting data exchange info");
+ continue;
+ }
+ end_points = hdp_get_end_points(rec);
+ if (!end_points) {
+ error("Error getting end points");
+ continue;
+ }
+ DBG("Get data exchange spec %d", data_spec);
+ }
+
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Not implemented yet");
+ g_dbus_send_message(device->conn, reply);
+}
+
static DBusMessage *get_health_instances(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
- const sdp_record_t *rec;
- guint8 data_spec;
+ struct btd_adapter *adapter;
+ struct instances_aux *cb_data;
+ bdaddr_t src, dst;
+ uuid_t uuid;
- rec = btd_device_get_record(device->dev, HDP_UUID);
+ adapter = device_get_adapter(device->dev);
+ adapter_get_address(adapter, &src);
+ device_get_address(device->dev, &dst);
- if (!rec) {
- DBG("No record found");
- goto error;
- }
+ cb_data = g_new0(struct instances_aux, 1);
+ cb_data->device = device;
+ cb_data->msg = dbus_message_ref(msg);
- if (!hdp_get_data_exchange_spec(rec, &data_spec))
- goto error;
- DBG("Get data exchange spec %d", data_spec);
-error:
+ bt_string2uuid(&uuid, HDP_UUID);
+ if (bt_search_service(&src, &dst, &uuid, sink_health_instances,
+ cb_data, NULL) == 0)
+ return NULL;
+
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
- "Cannot get the remote SDP record");
+ "Error getting remote information");
}
static void health_device_free(struct hdp_device *device)
@@ -119,7 +172,8 @@ static void dev_path_unregister(void *data)
}
static GDBusMethodTable device_methods[] = {
- { "GetHealthInstances", "", "a{sv}", get_health_instances },
+ { "GetHealthInstances", "", "a{sv}", get_health_instances,
+ G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 5397f11..731154b 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -781,6 +781,11 @@ static gboolean register_data_exchange_spec(struct hdp_config *config,
return TRUE;
}
+GSList *hdp_get_end_points(const sdp_record_t *rec)
+{
+ return NULL;
+}
+
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
diff --git a/health/hdp_util.h b/health/hdp_util.h
index 0fdaaec..beafa00 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -32,6 +32,7 @@
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 09/32] Adds functions to get remote suported features from its SDP record
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-9-git-send-email-santoscadenas@gmail.com>
---
health/hdp_util.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 69 insertions(+), 5 deletions(-)
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 731154b..0b39151 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -781,11 +781,6 @@ static gboolean register_data_exchange_spec(struct hdp_config *config,
return TRUE;
}
-GSList *hdp_get_end_points(const sdp_record_t *rec)
-{
- return NULL;
-}
-
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
@@ -887,3 +882,72 @@ gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
*val = exspec->val.uint8;
return TRUE;
}
+
+static gint cmp_feat_mdep(gconstpointer a, gconstpointer b)
+{
+ const struct hdp_supp_fts *fts = a;
+ const guint8 *mdep = b;
+
+ if (fts->mdepid == *mdep)
+ return 0;
+ return -1;
+}
+
+static GSList *get_feature(GSList *epl, sdp_data_t *feat_seq)
+{
+ struct hdp_supp_fts *fts;
+ struct hdp_feature *feat;
+ GSList *l;
+ sdp_data_t *mdepid, *dtype, *role, *desc;
+
+ mdepid = feat_seq;
+ if (!mdepid || mdepid->dtd != SDP_UINT8)
+ return epl;
+ dtype = mdepid->next;
+ if (!dtype || dtype->dtd != SDP_UINT16)
+ return epl;
+ role = dtype->next;
+ if (!role || role->dtd != SDP_UINT8)
+ return epl;
+ desc = role->next;
+
+ l = g_slist_find_custom(epl, &mdepid->val.uint8, cmp_feat_mdep);
+ if (l) {
+ fts = l->data;
+ if (fts->role != role->val.uint8)
+ return epl;
+ } else {
+ fts = g_new0(struct hdp_supp_fts, 1);
+ fts->mdepid = mdepid->val.uint8;
+ fts->role = role->val.uint8;
+ epl = g_slist_prepend(epl, fts);
+ }
+
+ feat = g_new0(struct hdp_feature, 1);
+ feat->dtype = dtype->val.uint16;
+ if (desc && desc->dtd == SDP_TEXT_STR8)
+ feat->dscr = g_strdup(desc->val.str);
+ fts->features = g_slist_prepend(fts->features, feat);
+ return epl;
+}
+
+GSList *hdp_get_end_points(const sdp_record_t *rec)
+{
+ GSList *epl = NULL;
+ sdp_data_t *end_points, *l;
+
+ end_points = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
+
+ if (end_points->dtd != SDP_SEQ8)
+ return NULL;
+
+ for (l = end_points->val.dataseq; l; l = l->next) {
+ if (l->dtd != SDP_SEQ8)
+ continue;
+ epl = get_feature(epl, l->val.dataseq);
+ }
+
+ g_slist_foreach(epl, print_features, NULL);
+
+ return epl;
+}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 10/32] Insert end_point in array returned by get_health_instances
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-10-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--
health/hdp_util.c | 2 -
2 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 4fb9d62..8690f0e 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -76,6 +76,43 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
+{
+ DBusMessageIter entry, array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, "end_points");
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ dbus_message_iter_close_container(&entry, &array);
+ dbus_message_iter_close_container(iter, &entry);
+}
+
+static void append_array_entry(DBusMessageIter *iter, uint32_t *handler,
+ uint8_t *spec, GSList *end_points)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "id", DBUS_TYPE_UINT32, handler);
+ dict_append_entry(&dict, "data_spec", DBUS_TYPE_BYTE, spec);
+ append_dict_features(&dict, end_points);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
{
struct instances_aux *cb_data = user_data;
@@ -86,6 +123,7 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
sdp_list_t *l;
guint8 data_spec;
GSList *end_points;
+ DBusMessageIter iter, dict;
g_free(cb_data);
@@ -97,10 +135,22 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
return;
}
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
for (l = recs; l; l = l->next) {
rec = l->data;
DBG("Record found 0x%x", rec->handle);
- /* TODO: Check record */
+
if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
error("Error getting data exchange info");
continue;
@@ -110,11 +160,15 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
error("Error getting end points");
continue;
}
- DBG("Get data exchange spec %d", data_spec);
+ append_array_entry(&dict, &rec->handle, &data_spec,
+ end_points);
}
+ dbus_message_iter_close_container(&iter, &dict);
+/*
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Not implemented yet");
+*/
g_dbus_send_message(device->conn, reply);
}
@@ -172,7 +226,7 @@ static void dev_path_unregister(void *data)
}
static GDBusMethodTable device_methods[] = {
- { "GetHealthInstances", "", "a{sv}", get_health_instances,
+ { "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 0b39151..2f09417 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -947,7 +947,5 @@ GSList *hdp_get_end_points(const sdp_record_t *rec)
epl = get_feature(epl, l->val.dataseq);
}
- g_slist_foreach(epl, print_features, NULL);
-
return epl;
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 11/32] Initial support for connecting instances
From: Jose Antonio Santos Cadenas @ 2010-06-04 8:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275640225-4186-11-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 8690f0e..8bb6057 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -76,6 +76,16 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
+{
+ const struct hdp_instance *hdpi = instance;
+ const uint32_t *id = p;
+
+ if (hdpi->id == *id)
+ return 0;
+ return -1;
+}
+
static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
{
DBusMessageIter entry, array;
@@ -225,9 +235,40 @@ static void dev_path_unregister(void *data)
health_device_free(device);
}
+static DBusMessage *hdp_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ struct hdp_instance *hdpi;
+ uint32_t lid, rid;
+ GSList *l;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &lid,
+ DBUS_TYPE_UINT32, &rid,
+ DBUS_TYPE_INVALID)) {
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ }
+
+ l = g_slist_find_custom(device->hdp_adapter->instances, &lid,
+ hdp_instance_idcmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid local instance id");
+ hdpi = l->data;
+
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
+ "Function is not yet implemented");
+}
+
static GDBusMethodTable device_methods[] = {
{ "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
+ { "Connect", "uu", "o", hdp_connect, G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
@@ -235,33 +276,30 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
struct btd_device *device)
{
const gchar *path = device_get_path(device);
+ struct btd_adapter *adapter = device_get_adapter(device);
struct hdp_device *dev;
dev = g_new0(struct hdp_device, 1);
dev->conn = dbus_connection_ref(conn);
dev->dev = btd_device_ref(device);
+ dev->hdp_adapter = find_adapter(adapters, adapter);
+
+ if (!dev->hdp_adapter)
+ goto fail;
if (!g_dbus_register_interface(conn, path,
HEALTH_DEVICE,
device_methods, NULL, NULL,
dev, dev_path_unregister)) {
error("D-Bus failed to register %s interface", HEALTH_DEVICE);
- health_device_free(dev);
- return NULL;
+ goto fail;
}
DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
return dev;
-}
-
-static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
-{
- const struct hdp_instance *hdpi = instance;
- const uint32_t *id = p;
-
- if (hdpi->id == *id)
- return 0;
- return -1;
+fail:
+ health_device_free(dev);
+ return NULL;
}
static void hdp_set_instance_id(struct hdp_instance *hdpi)
--
1.6.3.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox