Re: [PATCH BlueZ 4/4] GATT shim to src/shared bt_att

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Michael,

On Wednesday 12 of November 2014 12:22:59 Michael Janssen wrote:
> This patch implements a version of GAttrib which is backed by
> bt_att, which enables the simultaneous use of GAttrib and bt_att.
> 
> This should enable smooth transition of profiles from the GAttrib
> API to the src/shared bt_att API.
> ---
>  attrib/gattrib.c | 733
> ++++++++++++------------------------------------------- 1 file changed, 154
> insertions(+), 579 deletions(-)
> 
> diff --git a/attrib/gattrib.c b/attrib/gattrib.c
> index fa51b6d..b55e437 100644
> --- a/attrib/gattrib.c
> +++ b/attrib/gattrib.c
> @@ -36,227 +36,124 @@
>  #include <bluetooth/bluetooth.h>
> 
>  #include "btio/btio.h"
> -#include "lib/uuid.h"
> -#include "src/shared/util.h"
>  #include "src/log.h"
> -#include "attrib/att.h"
> +#include "src/shared/util.h"
> +#include "src/shared/att.h"
>  #include "attrib/gattrib.h"
> 
> -#define GATT_TIMEOUT 30
> -
>  struct _GAttrib {
> +	int ref_count;
> +	struct bt_att *att;
>  	GIOChannel *io;
> -	int refs;
> -	uint8_t *buf;
> -	size_t buflen;
> -	guint read_watch;
> -	guint write_watch;
> -	guint timeout_watch;
> -	GQueue *requests;
> -	GQueue *responses;
> -	GSList *events;
> -	guint next_cmd_id;
>  	GDestroyNotify destroy;
>  	gpointer destroy_user_data;
> -	bool stale;
> +	GQueue *callbacks;
> +	uint8_t *buf;
> +	int buflen;
>  };
> 
> -struct command {
> -	guint id;
> -	guint8 opcode;
> -	guint8 *pdu;
> -	guint16 len;
> -	guint8 expected;
> -	bool sent;
> -	GAttribResultFunc func;
> -	gpointer user_data;
> -	GDestroyNotify notify;
> -};
> 
> -struct event {
> -	guint id;
> -	guint8 expected;
> -	guint16 handle;
> -	GAttribNotifyFunc func;
> +struct attrib_callbacks {
> +	GAttribResultFunc result_func;
> +	GAttribNotifyFunc notify_func;
> +	GDestroyNotify destroy_func;
>  	gpointer user_data;
> -	GDestroyNotify notify;
> +	GAttrib *parent;
> +	uint16_t notify_handle;
>  };
> 
> -static guint8 opcode2expected(guint8 opcode)
> +GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
>  {
> -	switch (opcode) {
> -	case ATT_OP_MTU_REQ:
> -		return ATT_OP_MTU_RESP;
> -
> -	case ATT_OP_FIND_INFO_REQ:
> -		return ATT_OP_FIND_INFO_RESP;
> -
> -	case ATT_OP_FIND_BY_TYPE_REQ:
> -		return ATT_OP_FIND_BY_TYPE_RESP;
> -
> -	case ATT_OP_READ_BY_TYPE_REQ:
> -		return ATT_OP_READ_BY_TYPE_RESP;
> -
> -	case ATT_OP_READ_REQ:
> -		return ATT_OP_READ_RESP;
> -
> -	case ATT_OP_READ_BLOB_REQ:
> -		return ATT_OP_READ_BLOB_RESP;
> -
> -	case ATT_OP_READ_MULTI_REQ:
> -		return ATT_OP_READ_MULTI_RESP;
> +	gint fd;
> +	GAttrib *attr;
> 
> -	case ATT_OP_READ_BY_GROUP_REQ:
> -		return ATT_OP_READ_BY_GROUP_RESP;
> +	if (!io)
> +		return NULL;
> 
> -	case ATT_OP_WRITE_REQ:
> -		return ATT_OP_WRITE_RESP;
> +	fd = g_io_channel_unix_get_fd(io);
> +	attr = new0(GAttrib, 1);
> +	if (!attr)
> +		return NULL;
> 
> -	case ATT_OP_PREP_WRITE_REQ:
> -		return ATT_OP_PREP_WRITE_RESP;
> +	g_io_channel_ref(io);
> +	attr->io = io;
> 
> -	case ATT_OP_EXEC_WRITE_REQ:
> -		return ATT_OP_EXEC_WRITE_RESP;
> +	attr->att = bt_att_new(fd);
> +	if (!attr->att)
> +		goto fail;
> 
> -	case ATT_OP_HANDLE_IND:
> -		return ATT_OP_HANDLE_CNF;
> -	}
> +	attr->buf = g_malloc0(mtu);
> +	attr->buflen = mtu;
> +	if (!attr->buf)
> +		goto fail;
> 
> -	return 0;
> -}
> +	attr->callbacks = g_queue_new();
> +	if (!attr->callbacks)
> +		goto fail;
> 
> -static bool is_response(guint8 opcode)
> -{
> -	switch (opcode) {
> -	case ATT_OP_ERROR:
> -	case ATT_OP_MTU_RESP:
> -	case ATT_OP_FIND_INFO_RESP:
> -	case ATT_OP_FIND_BY_TYPE_RESP:
> -	case ATT_OP_READ_BY_TYPE_RESP:
> -	case ATT_OP_READ_RESP:
> -	case ATT_OP_READ_BLOB_RESP:
> -	case ATT_OP_READ_MULTI_RESP:
> -	case ATT_OP_READ_BY_GROUP_RESP:
> -	case ATT_OP_WRITE_RESP:
> -	case ATT_OP_PREP_WRITE_RESP:
> -	case ATT_OP_EXEC_WRITE_RESP:
> -	case ATT_OP_HANDLE_CNF:
> -		return true;
> -	}
> +	return g_attrib_ref(attr);
> 
> -	return false;
> -}
> -
> -static bool is_request(guint8 opcode)
> -{
> -	switch (opcode) {
> -	case ATT_OP_MTU_REQ:
> -	case ATT_OP_FIND_INFO_REQ:
> -	case ATT_OP_FIND_BY_TYPE_REQ:
> -	case ATT_OP_READ_BY_TYPE_REQ:
> -	case ATT_OP_READ_REQ:
> -	case ATT_OP_READ_BLOB_REQ:
> -	case ATT_OP_READ_MULTI_REQ:
> -	case ATT_OP_READ_BY_GROUP_REQ:
> -	case ATT_OP_WRITE_REQ:
> -	case ATT_OP_WRITE_CMD:
> -	case ATT_OP_PREP_WRITE_REQ:
> -	case ATT_OP_EXEC_WRITE_REQ:
> -		return true;
> -	}
> -
> -	return false;
> +fail:
> +	free(attr->buf);
> +	bt_att_unref(attr->att);
> +	g_io_channel_unref(io);
> +	free(attr);
> +	return NULL;
>  }
> 
>  GAttrib *g_attrib_ref(GAttrib *attrib)
>  {
> -	int refs;
> -
>  	if (!attrib)
>  		return NULL;
> 
> -	refs = __sync_add_and_fetch(&attrib->refs, 1);
> +	__sync_fetch_and_add(&attrib->ref_count, 1);
> 
> -	DBG("%p: ref=%d", attrib, refs);
> +	DBG("%p: g_attrib_ref=%d ", attrib, attrib->ref_count);
> 
>  	return attrib;
>  }
> 
> -static void command_destroy(struct command *cmd)
> +static void attrib_callbacks_destroy(void *user_data)
>  {
> -	if (cmd->notify)
> -		cmd->notify(cmd->user_data);
> +	struct attrib_callbacks *cb;
> 
> -	g_free(cmd->pdu);
> -	g_free(cmd);
> -}
> +	cb = (struct attrib_callbacks *)user_data;

This cast shouldn't be needed, user_data is void*.

> +	if (!user_data || !g_queue_remove(cb->parent->callbacks, user_data))
> +		return;
> 
> -static void event_destroy(struct event *evt)
> -{
> -	if (evt->notify)
> -		evt->notify(evt->user_data);
> +	if (cb->destroy_func)
> +		cb->destroy_func(cb->user_data);
> 
> -	g_free(evt);
> +	free(user_data);
>  }
> 
> -static void attrib_destroy(GAttrib *attrib)
> +void g_attrib_unref(GAttrib *attrib)
>  {
> -	GSList *l;
> -	struct command *c;
> -
> -	while ((c = g_queue_pop_head(attrib->requests)))
> -		command_destroy(c);
> -
> -	while ((c = g_queue_pop_head(attrib->responses)))
> -		command_destroy(c);
> -
> -	g_queue_free(attrib->requests);
> -	attrib->requests = NULL;
> -
> -	g_queue_free(attrib->responses);
> -	attrib->responses = NULL;
> +	struct attrib_callbacks *cb;
> 
> -	for (l = attrib->events; l; l = l->next)
> -		event_destroy(l->data);
> -
> -	g_slist_free(attrib->events);
> -	attrib->events = NULL;
> -
> -	if (attrib->timeout_watch > 0)
> -		g_source_remove(attrib->timeout_watch);
> -
> -	if (attrib->write_watch > 0)
> -		g_source_remove(attrib->write_watch);
> -
> -	if (attrib->read_watch > 0)
> -		g_source_remove(attrib->read_watch);
> +	if (!attrib)
> +		return;
> 
> -	if (attrib->io)
> -		g_io_channel_unref(attrib->io);
> +	DBG("%p: g_attrib_unref=%d ", attrib, attrib->ref_count-1);
> 
> -	g_free(attrib->buf);
> +	if (__sync_sub_and_fetch(&attrib->ref_count, 1))
> +		return;
> 
>  	if (attrib->destroy)
>  		attrib->destroy(attrib->destroy_user_data);
> 
> -	g_free(attrib);
> -}
> +	while ((cb = g_queue_peek_head(attrib->callbacks)))
> +		attrib_callbacks_destroy(cb);
> 
> -void g_attrib_unref(GAttrib *attrib)
> -{
> -	int refs;
> +	g_queue_free(attrib->callbacks);
> 
> -	if (!attrib)
> -		return;
> -
> -	refs = __sync_sub_and_fetch(&attrib->refs, 1);
> +	g_free(attrib->buf);
> 
> -	DBG("%p: ref=%d", attrib, refs);
> +	bt_att_unref(attrib->att);
> 
> -	if (refs > 0)
> -		return;
> +	g_io_channel_unref(attrib->io);
> 
> -	attrib_destroy(attrib);
> +	g_free(attrib);
>  }
> 
>  GIOChannel *g_attrib_get_channel(GAttrib *attrib)
> @@ -270,7 +167,7 @@ GIOChannel *g_attrib_get_channel(GAttrib *attrib)
>  gboolean g_attrib_set_destroy_function(GAttrib *attrib,
>  		GDestroyNotify destroy, gpointer user_data)
>  {
> -	if (attrib == NULL)
> +	if (!attrib)
>  		return FALSE;
> 
>  	attrib->destroy = destroy;
> @@ -279,380 +176,130 @@ gboolean g_attrib_set_destroy_function(GAttrib
> *attrib, return TRUE;
>  }
> 
> -static gboolean disconnect_timeout(gpointer data)
> -{
> -	struct _GAttrib *attrib = data;
> -	struct command *c;
> -
> -	g_attrib_ref(attrib);
> -
> -	c = g_queue_pop_head(attrib->requests);
> -	if (c == NULL)
> -		goto done;
> -
> -	if (c->func)
> -		c->func(ATT_ECODE_TIMEOUT, NULL, 0, c->user_data);
> -
> -	command_destroy(c);
> -
> -	while ((c = g_queue_pop_head(attrib->requests))) {
> -		if (c->func)
> -			c->func(ATT_ECODE_ABORTED, NULL, 0, c->user_data);
> -		command_destroy(c);
> -	}
> 
> -done:
> -	attrib->stale = true;
> -
> -	g_attrib_unref(attrib);
> -
> -	return FALSE;
> -}
> -
> -static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
> -								gpointer data)
> +static void attrib_callback_result(uint8_t opcode, const void *pdu,
> +				   uint16_t length, void *user_data)
>  {
> -	struct _GAttrib *attrib = data;
> -	struct command *cmd;
> -	GError *gerr = NULL;
> -	gsize len;
> -	GIOStatus iostat;
> -	GQueue *queue;
> -
> -	if (attrib->stale)
> -		return FALSE;
> -
> -	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
> -		return FALSE;
> -
> -	queue = attrib->responses;
> -	cmd = g_queue_peek_head(queue);
> -	if (cmd == NULL) {
> -		queue = attrib->requests;
> -		cmd = g_queue_peek_head(queue);
> -	}
> -	if (cmd == NULL)
> -		return FALSE;
> -
> -	/*
> -	 * Verify that we didn't already send this command. This can only
> -	 * happen with elementes from attrib->requests.
> -	 */
> -	if (cmd->sent)
> -		return FALSE;
> +	uint8_t *buf;
> +	struct attrib_callbacks *cb = user_data;
> +	guint8 status = 0;
> 
> -	iostat = g_io_channel_write_chars(io, (char *) cmd->pdu, cmd->len,
> -								&len, &gerr);
> -	if (iostat != G_IO_STATUS_NORMAL) {
> -		if (gerr) {
> -			error("%s", gerr->message);
> -			g_error_free(gerr);
> -		}
> +	if (!cb)
> +		return;
> 
> -		return FALSE;
> -	}
> +	buf = g_malloc0(length+1);
> +	if (!buf)
> +		return;

g_malloc0() will abort if memory allocation failed, should this be 
g_malloc0_try() ?  Also if this is not due to glib API requirement we should 
be using malloc0().

Also there should be spaces around +. (this is affecting multiple places)

> 
> -	if (cmd->expected == 0) {
> -		g_queue_pop_head(queue);
> -		command_destroy(cmd);
> +	buf[0] = opcode;
> +	memcpy(buf+1, pdu, length);
> 
> -		return TRUE;
> +	if (opcode == BT_ATT_OP_ERROR_RSP) {
> +		if (length < 4)

Should be < 5 if we are accessing buf[4].

> +			status = BT_ATT_ERROR_UNLIKELY;
> +		else
> +			status = buf[4];
>  	}
> 
> -	cmd->sent = true;
> -
> -	if (attrib->timeout_watch == 0)
> -		attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT,
> -						disconnect_timeout, attrib);
> +	if (cb->result_func)
> +		cb->result_func(status, buf, length+1, cb->user_data);
> 
> -	return FALSE;
> +	g_free(buf);
>  }
> 
> -static void destroy_sender(gpointer data)
> -{
> -	struct _GAttrib *attrib = data;
> 
> -	attrib->write_watch = 0;
> -	g_attrib_unref(attrib);
> -}
> -
> -static void wake_up_sender(struct _GAttrib *attrib)
> -{
> -	if (attrib->write_watch > 0)
> -		return;
> -
> -	attrib = g_attrib_ref(attrib);
> -	attrib->write_watch = g_io_add_watch_full(attrib->io,
> -				G_PRIORITY_DEFAULT, G_IO_OUT,
> -				can_write_data, attrib, destroy_sender);
> -}
> -
> -static bool match_event(struct event *evt, const uint8_t *pdu, gsize len)
> -{
> -	guint16 handle;
> -
> -	if (is_request(pdu[0]) && evt->expected == GATTRIB_ALL_REQS)
> -		return true;
> -
> -	if (evt->expected == pdu[0] && evt->handle == GATTRIB_ALL_HANDLES)
> -		return true;
> -
> -	if (len < 3)
> -		return false;
> -
> -	handle = get_le16(&pdu[1]);
> -
> -	if (evt->expected == pdu[0] && evt->handle == handle)
> -		return true;
> -
> -	return false;
> -}
> -
> -static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer
> data) +static void attrib_callback_notify(uint8_t opcode, const void *pdu,
> +				uint16_t length, void *user_data)
>  {
> -	struct _GAttrib *attrib = data;
> -	struct command *cmd = NULL;
> -	GSList *l;
> -	uint8_t buf[512], status;
> -	gsize len;
> -	GIOStatus iostat;
> -
> -	if (attrib->stale)
> -		return FALSE;
> -
> -	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> -		struct command *c;
> -
> -		while ((c = g_queue_pop_head(attrib->requests))) {
> -			if (c->func)
> -				c->func(ATT_ECODE_IO, NULL, 0, c->user_data);
> -			command_destroy(c);
> -		}
> -
> -		attrib->read_watch = 0;
> -
> -		return FALSE;
> -	}
> -
> -	memset(buf, 0, sizeof(buf));
> -
> -	iostat = g_io_channel_read_chars(io, (char *) buf, sizeof(buf),
> -								&len, NULL);
> -	if (iostat != G_IO_STATUS_NORMAL) {
> -		status = ATT_ECODE_IO;
> -		goto done;
> -	}
> -
> -	for (l = attrib->events; l; l = l->next) {
> -		struct event *evt = l->data;
> -
> -		if (match_event(evt, buf, len))
> -			evt->func(buf, len, evt->user_data);
> -	}
> -
> -	if (!is_response(buf[0]))
> -		return TRUE;
> -
> -	if (attrib->timeout_watch > 0) {
> -		g_source_remove(attrib->timeout_watch);
> -		attrib->timeout_watch = 0;
> -	}
> -
> -	cmd = g_queue_pop_head(attrib->requests);
> -	if (cmd == NULL) {
> -		/* Keep the watch if we have events to report */
> -		return attrib->events != NULL;
> -	}
> -
> -	if (buf[0] == ATT_OP_ERROR) {
> -		status = buf[4];
> -		goto done;
> -	}
> -
> -	if (cmd->expected != buf[0]) {
> -		status = ATT_ECODE_IO;
> -		goto done;
> -	}
> -
> -	status = 0;
> -
> -done:
> -	if (!g_queue_is_empty(attrib->requests) ||
> -					!g_queue_is_empty(attrib->responses))
> -		wake_up_sender(attrib);
> -
> -	if (cmd) {
> -		if (cmd->func)
> -			cmd->func(status, buf, len, cmd->user_data);
> -
> -		command_destroy(cmd);
> -	}
> +	uint8_t *buf;
> +	struct attrib_callbacks *cb = user_data;
> 
> -	return TRUE;
> -}
> +	if (!cb)
> +		return;
> 
> -GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
> -{
> -	struct _GAttrib *attrib;
> +	if (cb->notify_func == NULL)

Use ! for pointer checking. I know that we are not fully following this in 
full code base but lets be consistent in new code. 

> +		return;
> 
> -	g_io_channel_set_encoding(io, NULL, NULL);
> -	g_io_channel_set_buffered(io, FALSE);
> +	if (cb->notify_handle != GATTRIB_ALL_HANDLES && length < 2)
> +		return;
> 
> -	attrib = g_try_new0(struct _GAttrib, 1);
> -	if (attrib == NULL)
> -		return NULL;
> +	if (cb->notify_handle != GATTRIB_ALL_HANDLES &&
> +					     cb->notify_handle != get_le16(pdu))
> +		return;
> 
> -	attrib->buf = g_malloc0(mtu);
> -	attrib->buflen = mtu;
> +	buf = g_malloc0(length+1);
> +	if (!buf)
> +		return;

Same here:  use malloc0() or g_mallo0_try().

> 
> -	attrib->io = g_io_channel_ref(io);
> -	attrib->requests = g_queue_new();
> -	attrib->responses = g_queue_new();
> +	buf[0] = opcode;
> +	memcpy(buf+1, pdu, length);
> 
> -	attrib->read_watch = g_io_add_watch(attrib->io,
> -			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> -			received_data, attrib);
> +	cb->notify_func(buf, length+1, cb->user_data);
> 
> -	return g_attrib_ref(attrib);
> +	g_free(buf);
>  }
> 
>  guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16
> len, GAttribResultFunc func, gpointer user_data,
>  			GDestroyNotify notify)
>  {
> -	struct command *c;
> -	GQueue *queue;
> -	uint8_t opcode;
> -
> -	if (attrib->stale)
> -		return 0;
> +	struct attrib_callbacks *cb = NULL;
> +	bt_att_response_func_t response_cb = NULL;
> +	bt_att_destroy_func_t destroy_cb = NULL;
> 
> -	c = g_try_new0(struct command, 1);
> -	if (c == NULL)
> +	if (!pdu || !len)
>  		return 0;
> 
> -	opcode = pdu[0];
> -
> -	c->opcode = opcode;
> -	c->expected = opcode2expected(opcode);
> -	c->pdu = g_malloc(len);
> -	memcpy(c->pdu, pdu, len);
> -	c->len = len;
> -	c->func = func;
> -	c->user_data = user_data;
> -	c->notify = notify;
> -
> -	if (is_response(opcode))
> -		queue = attrib->responses;
> -	else
> -		queue = attrib->requests;
> -
> -	if (id) {
> -		c->id = id;
> -		if (!is_response(opcode))
> -			g_queue_push_head(queue, c);
> -		else
> -			/* Don't re-order responses even if an ID is given */
> -			g_queue_push_tail(queue, c);
> -	} else {
> -		c->id = ++attrib->next_cmd_id;
> -		g_queue_push_tail(queue, c);
> +	if (func || notify) {
> +		cb = new0(struct attrib_callbacks, 1);
> +		if (cb == 0)

if (!cb) ...  (this is affecting multiple places)

> +			return 0;
> +		cb->result_func = func;
> +		cb->user_data = user_data;
> +		cb->destroy_func = notify;
> +		cb->parent = attrib;
> +		g_queue_push_head(attrib->callbacks, cb);
> +		response_cb = attrib_callback_result;
> +		destroy_cb = attrib_callbacks_destroy;
>  	}
> 
> -	/*
> -	 * If a command was added to the queue and it was empty before, wake up
> -	 * the sender. If the sender was already woken up by the second queue,
> -	 * wake_up_sender will just return.
> -	 */
> -	if (g_queue_get_length(queue) == 1)
> -		wake_up_sender(attrib);
> -
> -	return c->id;
> -}
> -
> -static int command_cmp_by_id(gconstpointer a, gconstpointer b)
> -{
> -	const struct command *cmd = a;
> -	guint id = GPOINTER_TO_UINT(b);
> -
> -	return cmd->id - id;
> +	return bt_att_send(attrib->att, pdu[0], (void *)pdu+1, len-1,
> +						   response_cb, cb, destroy_cb);
>  }
> 
>  gboolean g_attrib_cancel(GAttrib *attrib, guint id)
>  {
> -	GList *l = NULL;
> -	struct command *cmd;
> -	GQueue *queue;
> -
> -	if (attrib == NULL)
> -		return FALSE;
> -
> -	queue = attrib->requests;
> -	if (queue)
> -		l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
> -					command_cmp_by_id);
> -	if (l == NULL) {
> -		queue = attrib->responses;
> -		if (!queue)
> -			return FALSE;
> -		l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
> -					command_cmp_by_id);
> -	}
> -
> -	if (l == NULL)
> -		return FALSE;
> -
> -	cmd = l->data;
> -
> -	if (cmd == g_queue_peek_head(queue) && cmd->sent)
> -		cmd->func = NULL;
> -	else {
> -		g_queue_remove(queue, cmd);
> -		command_destroy(cmd);
> -	}
> -
> -	return TRUE;
> +	return bt_att_cancel(attrib->att, id);
>  }
> 
> -static gboolean cancel_all_per_queue(GQueue *queue)
> +gboolean g_attrib_cancel_all(GAttrib *attrib)
>  {
> -	struct command *c, *head = NULL;
> -	gboolean first = TRUE;
> -
> -	if (queue == NULL)
> -		return FALSE;
> -
> -	while ((c = g_queue_pop_head(queue))) {
> -		if (first && c->sent) {
> -			/* If the command was sent ignore its callback ... */
> -			c->func = NULL;
> -			head = c;
> -			continue;
> -		}
> -
> -		first = FALSE;
> -		command_destroy(c);
> -	}
> -
> -	if (head) {
> -		/* ... and put it back in the queue */
> -		g_queue_push_head(queue, head);
> -	}
> -
> -	return TRUE;
> +	return bt_att_cancel_all(attrib->att);
>  }
> 
> -gboolean g_attrib_cancel_all(GAttrib *attrib)
> +guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
> +				GAttribNotifyFunc func, gpointer user_data,
> +				GDestroyNotify notify)
>  {
> -	gboolean ret;
> -
> -	if (attrib == NULL)
> -		return FALSE;
> +	struct attrib_callbacks *cb = NULL;
> +
> +	if (func || notify) {
> +		cb = new0(struct attrib_callbacks, 1);
> +		if (cb == 0)
> +			return 0;
> +		cb->notify_func = func;
> +		cb->notify_handle = handle;
> +		cb->user_data = user_data;
> +		cb->destroy_func = notify;
> +		cb->parent = attrib;
> +		g_queue_push_head(attrib->callbacks, cb);
> +	}
> 
> -	ret = cancel_all_per_queue(attrib->requests);
> -	ret = cancel_all_per_queue(attrib->responses) && ret;
> +	if (opcode == GATTRIB_ALL_REQS)
> +		opcode = BT_ATT_ALL_REQUESTS;
> 
> -	return ret;
> +	return bt_att_register(attrib->att, opcode, attrib_callback_notify,
> +			       cb, attrib_callbacks_destroy);
>  }
> 
>  uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
> @@ -661,98 +308,26 @@ uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t
> *len) return NULL;
> 
>  	*len = attrib->buflen;
> -
>  	return attrib->buf;
>  }
> 
>  gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
>  {
> -	if (mtu < ATT_DEFAULT_LE_MTU)
> -		return FALSE;
> -
> -	attrib->buf = g_realloc(attrib->buf, mtu);
> -
> -	attrib->buflen = mtu;
> -
> -	return TRUE;
> -}
> -
> -guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
> -				GAttribNotifyFunc func, gpointer user_data,
> -				GDestroyNotify notify)
> -{
> -	static guint next_evt_id = 0;
> -	struct event *event;
> -
> -	event = g_try_new0(struct event, 1);
> -	if (event == NULL)
> -		return 0;
> -
> -	event->expected = opcode;
> -	event->handle = handle;
> -	event->func = func;
> -	event->user_data = user_data;
> -	event->notify = notify;
> -	event->id = ++next_evt_id;
> -
> -	attrib->events = g_slist_append(attrib->events, event);
> -
> -	return event->id;
> -}
> -
> -static int event_cmp_by_id(gconstpointer a, gconstpointer b)
> -{
> -	const struct event *evt = a;
> -	guint id = GPOINTER_TO_UINT(b);
> +	/* Clients of this expect a buffer to use. */
> +	if (mtu > attrib->buflen) {
> +		attrib->buf = g_realloc(attrib->buf, mtu);
> +		attrib->buflen = mtu;
> +	}
> 
> -	return evt->id - id;
> +	return bt_att_set_mtu(attrib->att, mtu);
>  }
> 
>  gboolean g_attrib_unregister(GAttrib *attrib, guint id)
>  {
> -	struct event *evt;
> -	GSList *l;
> -
> -	if (id == 0) {
> -		warn("%s: invalid id", __func__);
> -		return FALSE;
> -	}
> -
> -	l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
> -							event_cmp_by_id);
> -	if (l == NULL)
> -		return FALSE;
> -
> -	evt = l->data;
> -
> -	attrib->events = g_slist_remove(attrib->events, evt);
> -
> -	if (evt->notify)
> -		evt->notify(evt->user_data);
> -
> -	g_free(evt);
> -
> -	return TRUE;
> +	return bt_att_unregister(attrib->att, id);
>  }
> 
>  gboolean g_attrib_unregister_all(GAttrib *attrib)
>  {
> -	GSList *l;
> -
> -	if (attrib->events == NULL)
> -		return FALSE;
> -
> -	for (l = attrib->events; l; l = l->next) {
> -		struct event *evt = l->data;
> -
> -		if (evt->notify)
> -			evt->notify(evt->user_data);
> -
> -		g_free(evt);
> -	}
> -
> -	g_slist_free(attrib->events);
> -	attrib->events = NULL;
> -
> -	return TRUE;
> +	return bt_att_unregister_all(attrib->att);
>  }

-- 
BR
Szymon Janc
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux