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 Wed, Nov 5, 2014 at 5:17 PM, Michael Janssen <jamuraa@xxxxxxxxxxxx> wrote:
> Hi Luiz,
>
> On Wed, Nov 5, 2014 at 6:49 AM, Luiz Augusto von Dentz
> <luiz.dentz@xxxxxxxxx> wrote:
>> Hi Michael,
>>
>> On Tue, Nov 4, 2014 at 11:19 PM, Michael Janssen <jamuraa@xxxxxxxxxxxx> 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 | 734 +++++++++++--------------------------------------------
>>>  1 file changed, 147 insertions(+), 587 deletions(-)
>>>
>>> diff --git a/attrib/gattrib.c b/attrib/gattrib.c
>>> index fa51b6d..63f219d 100644
>>> --- a/attrib/gattrib.c
>>> +++ b/attrib/gattrib.c
>>> @@ -2,8 +2,7 @@
>>>   *
>>>   *  BlueZ - Bluetooth protocol stack for Linux
>>>   *
>>> - *  Copyright (C) 2010  Nokia Corporation
>>> - *  Copyright (C) 2010  Marcel Holtmann <marcel@xxxxxxxxxxxx>
>>> + *  Copyright (C) 2014  Google, Inc.
>>
>> You got to be super careful with copyright changes, because of that we
>> usually request this to be in a separate patch, except for newly
>> created files of course. To speed up this I would suggest you leave
>> this for later.
>
> To be clear: this looking like a change of a bunch of lines of a
> single file is an artifact of the patch process - I created this from
> an empty file by copying the headers from gattrib.h and implementing
> them.  It was originally a new file called gattrib-shared.c.  Normally
> I wouldn't change this copyright stuff and have no issue keeping the
> changes for v2.

You can try -B option of format patch, that should show up as a
complete rewrite.

>>>   *
>>>   *
>>>   *  This program is free software; you can redistribute it and/or modify
>>> @@ -36,227 +35,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;
>>> +       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 +166,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 +175,116 @@ 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)
>>> -{
>>> -       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;
>>> -
>>> -       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);
>>> -               }
>>> -
>>> -               return FALSE;
>>> -       }
>>> -
>>> -       if (cmd->expected == 0) {
>>> -               g_queue_pop_head(queue);
>>> -               command_destroy(cmd);
>>>
>>> -               return TRUE;
>>> -       }
>>> -
>>> -       cmd->sent = true;
>>> -
>>> -       if (attrib->timeout_watch == 0)
>>> -               attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT,
>>> -                                               disconnect_timeout, attrib);
>>> -
>>> -       return FALSE;
>>> -}
>>> -
>>> -static void destroy_sender(gpointer data)
>>> +static void attrib_callback_result(uint8_t opcode, const void *pdu,
>>> +                                  uint16_t length, void *user_data)
>>>  {
>>> -       struct _GAttrib *attrib = data;
>>> -
>>> -       attrib->write_watch = 0;
>>> -       g_attrib_unref(attrib);
>>> -}
>>> +       uint8_t *buf;
>>> +       struct attrib_callbacks *cb = user_data;
>>>
>>> -static void wake_up_sender(struct _GAttrib *attrib)
>>> -{
>>> -       if (attrib->write_watch > 0)
>>> +       if (!cb)
>>>                 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;
>>> +       buf = g_malloc0(length+1);
>>> +       if (!buf)
>>> +               return;
>>>
>>> -       handle = get_le16(&pdu[1]);
>>> +       buf[0] = opcode;
>>> +       memcpy(buf+1, pdu, length);
>>>
>>> -       if (evt->expected == pdu[0] && evt->handle == handle)
>>> -               return true;
>>> +       if (cb->result_func)
>>> +               cb->result_func(0, buf, length+1, cb->user_data);
>>>
>>> -       return false;
>>> +       g_free(buf);
>>>  }
>>>
>>> -static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer 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);
>>> -       }
>>> +static void attrib_callback_notify(uint8_t opcode, const void *pdu,
>>> +                               uint16_t length, void *user_data)
>>> +{
>>> +       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)
>>> +               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;
>>>
>>> -       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;
>>> -
>>> -       c = g_try_new0(struct command, 1);
>>> -       if (c == NULL)
>>> -               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);
>>> +       struct attrib_callbacks *cb = NULL;
>>> +       bt_att_response_func_t response_cb = NULL;
>>> +       bt_att_destroy_func_t destroy_cb = NULL;
>>> +
>>> +       if (func || notify) {
>>> +               cb = new0(struct attrib_callbacks, 1);
>>> +               if (cb == 0)
>>> +                       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;
>>> -
>>> -       ret = cancel_all_per_queue(attrib->requests);
>>> -       ret = cancel_all_per_queue(attrib->responses) && ret;
>>> +       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);
>>> +       }
>>>
>>> -       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 +293,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);
>>>  }
>>> --
>>> 2.1.0.rc2.206.gedb03e5
>>>
>>> --
>>> 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
>>
>>
>>
>> --
>> Luiz Augusto von Dentz



-- 
Luiz Augusto von Dentz
--
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