* Re: [PATCH] Bluetooth: Remove unneeded zero init
From: Marcel Holtmann @ 2012-08-30 15:06 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1346317467-20903-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
> hdev is allocated with kzalloc so zero initialization is not needed.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/hci_core.h | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 36720f0..05bcea6 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -443,10 +443,8 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
> static inline void hci_conn_hash_init(struct hci_dev *hdev)
> {
> struct hci_conn_hash *h = &hdev->conn_hash;
> +
> INIT_LIST_HEAD(&h->list);
> - h->acl_num = 0;
> - h->sco_num = 0;
> - h->le_num = 0;
> }
since there is only one user of hci_conn_hash_init, we should just
replace that call with a direct INIT_LIST_HEAD.
Regards
Marcel
^ permalink raw reply
* [PATCH BlueZ] build: Use AC_USE_SYSTEM_EXTENSIONS for POSIX/C extensions
From: Anderson Lizardo @ 2012-08-30 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
Using this macro in configure.ac enables certain extensions that BlueZ
currently depends on. The macro is recommended instead of defining
_GNU_SOURCE on each C file.
---
configure.ac | 2 ++
src/adapter.c | 1 -
src/event.c | 1 -
src/sdp-xml.c | 1 -
src/textfile.c | 1 -
tools/ciptool.c | 1 -
tools/hciattach.c | 1 -
tools/rfcomm.c | 1 -
8 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 7d9a34d..6c897d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,6 +10,8 @@ AM_MAINTAINER_MODE
PKG_PROG_PKG_CONFIG
+AC_USE_SYSTEM_EXTENSIONS
+
AC_INIT_BLUEZ
COMPILER_FLAGS
diff --git a/src/adapter.c b/src/adapter.c
index 50779fd..e400603 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -26,7 +26,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
diff --git a/src/event.c b/src/event.c
index 1586293..3b49dce 100644
--- a/src/event.c
+++ b/src/event.c
@@ -26,7 +26,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
diff --git a/src/sdp-xml.c b/src/sdp-xml.c
index 52df285..1aca776 100644
--- a/src/sdp-xml.c
+++ b/src/sdp-xml.c
@@ -25,7 +25,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
diff --git a/src/textfile.c b/src/textfile.c
index 9d88fbc..b6a7e1f 100644
--- a/src/textfile.c
+++ b/src/textfile.c
@@ -25,7 +25,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
diff --git a/tools/ciptool.c b/tools/ciptool.c
index edce9da..e240f38 100644
--- a/tools/ciptool.c
+++ b/tools/ciptool.c
@@ -25,7 +25,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
diff --git a/tools/hciattach.c b/tools/hciattach.c
index d19fa33..e166730 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -27,7 +27,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/tools/rfcomm.c b/tools/rfcomm.c
index e8bdd0f..affdbc7 100644
--- a/tools/rfcomm.c
+++ b/tools/rfcomm.c
@@ -25,7 +25,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH BlueZ] input: Fix build error due to O_CLOEXEC
From: Anderson Lizardo @ 2012-08-30 13:16 UTC (permalink / raw)
To: Lucas De Marchi; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_Ng=92JbYvZHkMnvBJssRERqCsE3_bDwx+ZoymE7_B7ZQ@mail.gmail.com>
Hi Lucas,
On Tue, Aug 28, 2012 at 8:55 PM, Anderson Lizardo
<anderson.lizardo@openbossa.org> wrote:
> On Tue, Aug 28, 2012 at 8:15 PM, Lucas De Marchi
> <lucas.demarchi@profusion.mobi> wrote:
>>> +#define _GNU_SOURCE
>>
>> this should be already in our config.h. It seems like we are missing
>> the following in our configure.ac:
>>
>> AC_USE_SYSTEM_EXTENSIONS.
>>
>> Btw, we should remove the other definitions of _GNU_SOURCE
>
> Nice, I wasn't aware of this feature. Does it require any newer
> autoconf version?
>
> I can try this tomorrow and send a new patch set removing the
> _GNU_SOURCE defines.
I just sent a new patch using this macro (it exists since autoconf
2.60). Thanks for the heads up.
Johan: please apply the new patch "build: Use AC_USE_SYSTEM_EXTENSIONS
for POSIX/C extensions" instead of this one.
Thanks,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* [PATCH hcidump] amp: Decode Read Data Block Size HCI cmd
From: Andrei Emeltchenko @ 2012-08-30 13:06 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Decode Read Data Block Size HCI command and command status.
< HCI Command: Read Data Block Size (0x04|0x000a) plen 0
> HCI Event: Command Complete (0x0e) plen 10
Read Data Block Size (0x04|0x000a) ncmd 1
status 0x00
Max ACL 1492 Block len 1492 Num blocks 4
---
lib/hci.h | 8 ++++++++
parser/hci.c | 24 +++++++++++++++++++++++-
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/lib/hci.h b/lib/hci.h
index 3dbb221..d068a2f 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -1316,6 +1316,14 @@ typedef struct {
} __attribute__ ((packed)) read_bd_addr_rp;
#define READ_BD_ADDR_RP_SIZE 7
+#define OCF_READ_DATA_BLOCK_SIZE 0x000A
+typedef struct {
+ uint8_t status;
+ uint16_t max_acl_len;
+ uint16_t data_block_len;
+ uint16_t num_blocks;
+} __attribute__ ((packed)) read_data_block_size_rp;
+
/* Status params */
#define OGF_STATUS_PARAM 0x05
diff --git a/parser/hci.c b/parser/hci.c
index 115cf1e..38794bd 100644
--- a/parser/hci.c
+++ b/parser/hci.c
@@ -338,7 +338,7 @@ static char *cmd_hostctl_str[CMD_HOSTCTL_NUM + 1] = {
"Write LE Host Supported",
};
-#define CMD_INFO_NUM 9
+#define CMD_INFO_NUM 10
static char *cmd_info_str[CMD_INFO_NUM + 1] = {
"Unknown",
"Read Local Version Information",
@@ -350,6 +350,7 @@ static char *cmd_info_str[CMD_INFO_NUM + 1] = {
"Read Country Code",
"Unknown",
"Read BD ADDR",
+ "Read Data Block Size",
};
#define CMD_STATUS_NUM 11
@@ -2041,6 +2042,24 @@ static inline void bdaddr_response_dump(int level, struct frame *frm)
raw_dump(level, frm);
}
+static inline void read_data_block_size_dump(int level, struct frame *frm)
+{
+ read_data_block_size_rp *rp = frm->ptr;
+
+ p_indent(level, frm);
+ printf("status 0x%2.2x\n", rp->status);
+
+ if (rp->status > 0) {
+ p_indent(level, frm);
+ printf("Error: %s\n", status2str(rp->status));
+ } else {
+ p_indent(level, frm);
+ printf("Max ACL %d Block len %d Num blocks %d\n",
+ btohs(rp->max_acl_len), btohs(rp->data_block_len),
+ btohs(rp->num_blocks));
+ }
+}
+
static inline void generic_response_dump(int level, struct frame *frm)
{
uint8_t status = get_u8(frm);
@@ -2886,6 +2905,9 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
case OCF_READ_BD_ADDR:
bdaddr_response_dump(level, frm);
return;
+ case OCF_READ_DATA_BLOCK_SIZE:
+ read_data_block_size_dump(level, frm);
+ return;
}
break;
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH] adapter: add API to find an existing device by D-Bus path
From: Daniele Forsi @ 2012-08-30 13:03 UTC (permalink / raw)
To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1346328542-13203-1-git-send-email-chen.ganir@ti.com>
2012/8/30 <chen.ganir@ti...>:
> + for (l = adapter->devices; l != NULL; l = g_slist_next(l))
> + if (g_strcmp0(device_get_path(l->data), path) == 0)
> + break;
what about returning l->data here instead of breaking the loop, so you
don't need the following NULL check?
> +
> + if (!l)
> + return NULL;
> +
> + return l->data;
> +}
--
Daniele Forsi
^ permalink raw reply
* Re: [PATCH v2] gatt: Translate Characteristic names
From: Szymon Janc @ 2012-08-30 12:43 UTC (permalink / raw)
To: Chen Ganir; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <503F5EAC.4070909@ti.com>
On Thursday 30 of August 2012 15:38:04 Chen Ganir wrote:
> >> static GSList *gatt_services = NULL;
> >>
> >> +static const struct characteristic_info *get_char_info(const char* uuid)
> >
> > I would leave this function returning name directly and not whole struct characteristic_info.
> >
> Why ? We have this struct with characteristic information (maybe later
> we'll add more information. Why limit ourselves to name only ?
If you plan to add more data into that structure then it is OK to return whole struct.
But if only name is to be used, then I would just call that function get_name() and
return name.
--
BR
Szymon Janc
^ permalink raw reply
* Re: [PATCH v2] gatt: Translate Characteristic names
From: Chen Ganir @ 2012-08-30 12:38 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1472845.YqRC14yUFc@uw000953>
Szymon,
On 08/30/2012 03:20 PM, Szymon Janc wrote:
> On Wednesday 29 of August 2012 13:56:16 chen.ganir@ti.com wrote:
>> From: Chen Ganir <chen.ganir@ti.com>
>
> Hi Chen,
>
>> Translate Characteristic UUID's to name. This list was taken from
>> the Bluetooth SIG developer site.
>> ---
>> attrib/client.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 80 insertions(+), 3 deletions(-)
>>
>> diff --git a/attrib/client.c b/attrib/client.c
>> index bb6adf8..4ef74b5 100644
>> --- a/attrib/client.c
>> +++ b/attrib/client.c
>> @@ -105,8 +105,79 @@ struct watcher {
>> struct gatt_service *gatt;
>> };
>>
>> +struct characteristic_info {
>> + const char *uuid;
>> + const char *name;
>> +};
>> +
>> +static const struct characteristic_info charInfo[] = {
>> + {"00002a43-0000-1000-8000-00805f9b34fb","Alert Category ID" },
>> + {"00002a42-0000-1000-8000-00805f9b34fb","Alert Category ID Bit Mask" },
>> + {"00002a06-0000-1000-8000-00805f9b34fb","Alert Level" },
>> + {"00002a44-0000-1000-8000-00805f9b34fb","Alert Notification Control Point" },
>> + {"00002a3f-0000-1000-8000-00805f9b34fb","Alert Status" },
>> + {"00002a01-0000-1000-8000-00805f9b34fb","Appearance" },
>> + {"00002a49-0000-1000-8000-00805f9b34fb","Blood Pressure Feature" },
>> + {"00002a35-0000-1000-8000-00805f9b34fb","Blood Pressure Measurement" },
>> + {"00002a38-0000-1000-8000-00805f9b34fb","Body Sensor Location" },
>> + {"00002a2b-0000-1000-8000-00805f9b34fb","Current Time" },
>> + {"00002a08-0000-1000-8000-00805f9b34fb","Date Time" },
>> + {"00002a0a-0000-1000-8000-00805f9b34fb","Day Date Time" },
>> + {"00002a09-0000-1000-8000-00805f9b34fb","Day of Week" },
>> + {"00002a00-0000-1000-8000-00805f9b34fb","Device Name" },
>> + {"00002a0d-0000-1000-8000-00805f9b34fb","DST Offset" },
>> + {"00002a0c-0000-1000-8000-00805f9b34fb","Exact Time 256" },
>> + {"00002a26-0000-1000-8000-00805f9b34fb","Firmware Revision String" },
>> + {"00002a27-0000-1000-8000-00805f9b34fb","Hardware Revision String" },
>> + {"00002a39-0000-1000-8000-00805f9b34fb","Heart Rate Control Point" },
>> + {"00002a37-0000-1000-8000-00805f9b34fb","Heart Rate Measurement" },
>> + {"00002a2a-0000-1000-8000-00805f9b34fb","IEEE 11073-20601 Regulatory" },
>> + {"00002a36-0000-1000-8000-00805f9b34fb","Intermediate Cuff Pressure" },
>> + {"00002a1e-0000-1000-8000-00805f9b34fb","Intermediate Temperature" },
>> + {"00002a0f-0000-1000-8000-00805f9b34fb","Local Time Information" },
>> + {"00002a29-0000-1000-8000-00805f9b34fb","Manufacturer Name String" },
>> + {"00002a21-0000-1000-8000-00805f9b34fb","Measurement Interval" },
>> + {"00002a24-0000-1000-8000-00805f9b34fb","Model Number String" },
>> + {"00002a46-0000-1000-8000-00805f9b34fb","New Alert" },
>> + {"00002a04-0000-1000-8000-00805f9b34fb","Peripheral Preferred Connection Parameters" },
>> + {"00002a02-0000-1000-8000-00805f9b34fb","Peripheral Privacy Flag" },
>> + {"00002a03-0000-1000-8000-00805f9b34fb","Reconnection Address" },
>> + {"00002a14-0000-1000-8000-00805f9b34fb","Reference Time Information" },
>> + {"00002a40-0000-1000-8000-00805f9b34fb","Ringer Control Point" },
>> + {"00002a41-0000-1000-8000-00805f9b34fb","Ringer Setting" },
>> + {"00002a25-0000-1000-8000-00805f9b34fb","Serial Number String" },
>> + {"00002a05-0000-1000-8000-00805f9b34fb","Service Changed" },
>> + {"00002a28-0000-1000-8000-00805f9b34fb","Software Revision String" },
>> + {"00002a47-0000-1000-8000-00805f9b34fb","Supported New Alert Category" },
>> + {"00002a48-0000-1000-8000-00805f9b34fb","Supported Unread Alert Category" },
>> + {"00002a23-0000-1000-8000-00805f9b34fb","System ID" },
>> + {"00002a1c-0000-1000-8000-00805f9b34fb","Temperature Measurement" },
>> + {"00002a1d-0000-1000-8000-00805f9b34fb","Temperature Type" },
>> + {"00002a12-0000-1000-8000-00805f9b34fb","Time Accuracy" },
>> + {"00002a13-0000-1000-8000-00805f9b34fb","Time Source" },
>> + {"00002a16-0000-1000-8000-00805f9b34fb","Time Update Control Point" },
>> + {"00002a17-0000-1000-8000-00805f9b34fb","Time Update State" },
>> + {"00002a11-0000-1000-8000-00805f9b34fb","Time with DST" },
>> + {"00002a0e-0000-1000-8000-00805f9b34fb","Time Zone" },
>> + {"00002a07-0000-1000-8000-00805f9b34fb","Tx Power Level" },
>> + {"00002a45-0000-1000-8000-00805f9b34fb","Unread Alert Status" },
>> + { }
>> +};
>> +
>> static GSList *gatt_services = NULL;
>>
>> +static const struct characteristic_info *get_char_info(const char* uuid)
>
> I would leave this function returning name directly and not whole struct characteristic_info.
>
Why ? We have this struct with characteristic information (maybe later
we'll add more information. Why limit ourselves to name only ?
>> +{
>> + const struct characteristic_info *c;
>> +
>> + for (c = charInfo; c->uuid; c++) {
>> + if(g_strcmp0(c->uuid, uuid) == 0) {
>> + return c;
>> + }
>> + }
>> + return NULL;
>> +}
>> +
>> static void characteristic_free(void *user_data)
>> {
>> struct characteristic *chr = user_data;
>> @@ -190,7 +261,7 @@ static int watcher_cmp(gconstpointer a, gconstpointer b)
>> static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
>> {
>> DBusMessageIter dict;
>> - const char *name = "";
>> + const struct characteristic_info *char_info;
>> char *uuid;
>>
>> dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
>> @@ -202,8 +273,14 @@ static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
>> dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
>> g_free(uuid);
>>
>> - /* FIXME: Translate UUID to name. */
>> - dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
>> + char_info = get_char_info(chr->type);
>> +
>> + if (char_info != NULL) {
>> + const char *name = char_info->name;
>> + if (name != NULL)
>> + dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
>> + }
>> +
>>
>> if (chr->desc)
>> dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
>>
>
BR,
Chen Ganir
^ permalink raw reply
* [PATCH] attrib: Check key size when verifying requirements
From: chen.ganir @ 2012-08-30 12:35 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
From: Chen Ganir <chen.ganir@ti.com>
The attrib server should return an error in case the channel is
encrypted but the key size is not sufficient. For now, simply check that
the key size is at least 7, which is the minimal allowed key size.
---
attrib/gattrib.c | 12 ++++++++++++
attrib/gattrib.h | 1 +
src/attrib-server.c | 3 +++
3 files changed, 16 insertions(+)
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 108d1d3..59bad6f 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -678,6 +678,18 @@ gboolean g_attrib_is_encrypted(GAttrib *attrib)
return sec_level > BT_IO_SEC_LOW;
}
+gboolean g_attrib_is_keysize_sufficient(GAttrib *attrib)
+{
+ uint8_t key_size;
+
+ if (!bt_io_get(attrib->io, NULL,
+ BT_IO_OPT_KEY_SIZE, &key_size,
+ BT_IO_OPT_INVALID))
+ return FALSE;
+
+ return key_size >= 7;
+}
+
gboolean g_attrib_unregister(GAttrib *attrib, guint id)
{
struct event *evt;
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
index bcff039..1935921 100644
--- a/attrib/gattrib.h
+++ b/attrib/gattrib.h
@@ -65,6 +65,7 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
GDestroyNotify notify);
gboolean g_attrib_is_encrypted(GAttrib *attrib);
+gboolean g_attrib_is_keysize_sufficient(GAttrib *attrib);
uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len);
gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu);
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5cb1383..cf40ac8 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -376,6 +376,9 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
channel->encrypted = g_attrib_is_encrypted(channel->attrib);
if (reqs == ATT_AUTHENTICATION && !channel->encrypted)
return ATT_ECODE_AUTHENTICATION;
+ else if (reqs == ATT_AUTHENTICATION &&
+ !g_attrib_is_keysize_sufficient(channel->attrib))
+ return ATT_ECODE_INSUFF_ENCR_KEY_SIZE;
else if (reqs == ATT_AUTHORIZATION)
return ATT_ECODE_AUTHORIZATION;
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v2] gatt: Translate Characteristic names
From: Szymon Janc @ 2012-08-30 12:20 UTC (permalink / raw)
To: chen.ganir@ti.com; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1346237776-12781-1-git-send-email-chen.ganir@ti.com>
On Wednesday 29 of August 2012 13:56:16 chen.ganir@ti.com wrote:
> From: Chen Ganir <chen.ganir@ti.com>
Hi Chen,
> Translate Characteristic UUID's to name. This list was taken from
> the Bluetooth SIG developer site.
> ---
> attrib/client.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 80 insertions(+), 3 deletions(-)
>
> diff --git a/attrib/client.c b/attrib/client.c
> index bb6adf8..4ef74b5 100644
> --- a/attrib/client.c
> +++ b/attrib/client.c
> @@ -105,8 +105,79 @@ struct watcher {
> struct gatt_service *gatt;
> };
>
> +struct characteristic_info {
> + const char *uuid;
> + const char *name;
> +};
> +
> +static const struct characteristic_info charInfo[] = {
> + {"00002a43-0000-1000-8000-00805f9b34fb","Alert Category ID" },
> + {"00002a42-0000-1000-8000-00805f9b34fb","Alert Category ID Bit Mask" },
> + {"00002a06-0000-1000-8000-00805f9b34fb","Alert Level" },
> + {"00002a44-0000-1000-8000-00805f9b34fb","Alert Notification Control Point" },
> + {"00002a3f-0000-1000-8000-00805f9b34fb","Alert Status" },
> + {"00002a01-0000-1000-8000-00805f9b34fb","Appearance" },
> + {"00002a49-0000-1000-8000-00805f9b34fb","Blood Pressure Feature" },
> + {"00002a35-0000-1000-8000-00805f9b34fb","Blood Pressure Measurement" },
> + {"00002a38-0000-1000-8000-00805f9b34fb","Body Sensor Location" },
> + {"00002a2b-0000-1000-8000-00805f9b34fb","Current Time" },
> + {"00002a08-0000-1000-8000-00805f9b34fb","Date Time" },
> + {"00002a0a-0000-1000-8000-00805f9b34fb","Day Date Time" },
> + {"00002a09-0000-1000-8000-00805f9b34fb","Day of Week" },
> + {"00002a00-0000-1000-8000-00805f9b34fb","Device Name" },
> + {"00002a0d-0000-1000-8000-00805f9b34fb","DST Offset" },
> + {"00002a0c-0000-1000-8000-00805f9b34fb","Exact Time 256" },
> + {"00002a26-0000-1000-8000-00805f9b34fb","Firmware Revision String" },
> + {"00002a27-0000-1000-8000-00805f9b34fb","Hardware Revision String" },
> + {"00002a39-0000-1000-8000-00805f9b34fb","Heart Rate Control Point" },
> + {"00002a37-0000-1000-8000-00805f9b34fb","Heart Rate Measurement" },
> + {"00002a2a-0000-1000-8000-00805f9b34fb","IEEE 11073-20601 Regulatory" },
> + {"00002a36-0000-1000-8000-00805f9b34fb","Intermediate Cuff Pressure" },
> + {"00002a1e-0000-1000-8000-00805f9b34fb","Intermediate Temperature" },
> + {"00002a0f-0000-1000-8000-00805f9b34fb","Local Time Information" },
> + {"00002a29-0000-1000-8000-00805f9b34fb","Manufacturer Name String" },
> + {"00002a21-0000-1000-8000-00805f9b34fb","Measurement Interval" },
> + {"00002a24-0000-1000-8000-00805f9b34fb","Model Number String" },
> + {"00002a46-0000-1000-8000-00805f9b34fb","New Alert" },
> + {"00002a04-0000-1000-8000-00805f9b34fb","Peripheral Preferred Connection Parameters" },
> + {"00002a02-0000-1000-8000-00805f9b34fb","Peripheral Privacy Flag" },
> + {"00002a03-0000-1000-8000-00805f9b34fb","Reconnection Address" },
> + {"00002a14-0000-1000-8000-00805f9b34fb","Reference Time Information" },
> + {"00002a40-0000-1000-8000-00805f9b34fb","Ringer Control Point" },
> + {"00002a41-0000-1000-8000-00805f9b34fb","Ringer Setting" },
> + {"00002a25-0000-1000-8000-00805f9b34fb","Serial Number String" },
> + {"00002a05-0000-1000-8000-00805f9b34fb","Service Changed" },
> + {"00002a28-0000-1000-8000-00805f9b34fb","Software Revision String" },
> + {"00002a47-0000-1000-8000-00805f9b34fb","Supported New Alert Category" },
> + {"00002a48-0000-1000-8000-00805f9b34fb","Supported Unread Alert Category" },
> + {"00002a23-0000-1000-8000-00805f9b34fb","System ID" },
> + {"00002a1c-0000-1000-8000-00805f9b34fb","Temperature Measurement" },
> + {"00002a1d-0000-1000-8000-00805f9b34fb","Temperature Type" },
> + {"00002a12-0000-1000-8000-00805f9b34fb","Time Accuracy" },
> + {"00002a13-0000-1000-8000-00805f9b34fb","Time Source" },
> + {"00002a16-0000-1000-8000-00805f9b34fb","Time Update Control Point" },
> + {"00002a17-0000-1000-8000-00805f9b34fb","Time Update State" },
> + {"00002a11-0000-1000-8000-00805f9b34fb","Time with DST" },
> + {"00002a0e-0000-1000-8000-00805f9b34fb","Time Zone" },
> + {"00002a07-0000-1000-8000-00805f9b34fb","Tx Power Level" },
> + {"00002a45-0000-1000-8000-00805f9b34fb","Unread Alert Status" },
> + { }
> +};
> +
> static GSList *gatt_services = NULL;
>
> +static const struct characteristic_info *get_char_info(const char* uuid)
I would leave this function returning name directly and not whole struct characteristic_info.
> +{
> + const struct characteristic_info *c;
> +
> + for (c = charInfo; c->uuid; c++) {
> + if(g_strcmp0(c->uuid, uuid) == 0) {
> + return c;
> + }
> + }
> + return NULL;
> +}
> +
> static void characteristic_free(void *user_data)
> {
> struct characteristic *chr = user_data;
> @@ -190,7 +261,7 @@ static int watcher_cmp(gconstpointer a, gconstpointer b)
> static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
> {
> DBusMessageIter dict;
> - const char *name = "";
> + const struct characteristic_info *char_info;
> char *uuid;
>
> dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
> @@ -202,8 +273,14 @@ static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
> dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
> g_free(uuid);
>
> - /* FIXME: Translate UUID to name. */
> - dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
> + char_info = get_char_info(chr->type);
> +
> + if (char_info != NULL) {
> + const char *name = char_info->name;
> + if (name != NULL)
> + dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
> + }
> +
>
> if (chr->desc)
> dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
>
--
BR
Szymon Janc
^ permalink raw reply
* [PATCH] adapter: add API to find an existing device by D-Bus path
From: chen.ganir @ 2012-08-30 12:09 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
From: Chen Ganir <chen.ganir@ti.com>
This allows us to get a btd_device from information passed in D-Bus
method calls or signals.
---
src/adapter.c | 15 +++++++++++++++
src/adapter.h | 2 ++
2 files changed, 17 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 50779fd..6aee982 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3479,6 +3479,21 @@ void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
}
}
+struct btd_device *adapter_get_device_by_path(struct btd_adapter *adapter,
+ const char *path)
+{
+ GSList *l;
+
+ for (l = adapter->devices; l != NULL; l = g_slist_next(l))
+ if (g_strcmp0(device_get_path(l->data), path) == 0)
+ break;
+
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
{
return mgmt_read_local_oob_data(adapter->dev_id);
diff --git a/src/adapter.h b/src/adapter.h
index 5a0247e..6435dfb 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -232,3 +232,5 @@ int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
int btd_adapter_ssp_enabled(struct btd_adapter *adapter);
+struct btd_device *adapter_get_device_by_path(struct btd_adapter *adapter,
+ const char *path);
--
1.7.9.5
^ permalink raw reply related
* [PATCH] adapter: add API to get the current list of devices
From: chen.ganir @ 2012-08-30 12:02 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
From: Chen Ganir <chen.ganir@ti.com>
This allows internal components to traverse the existing device list.
---
src/adapter.c | 5 +++++
src/adapter.h | 2 ++
2 files changed, 7 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index 50779fd..42ecae9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3479,6 +3479,11 @@ void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
}
}
+GSList *adapter_get_devices(struct btd_adapter *adapter)
+{
+ return adapter->devices;
+}
+
int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
{
return mgmt_read_local_oob_data(adapter->dev_id);
diff --git a/src/adapter.h b/src/adapter.h
index 5a0247e..4cda9c8 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -232,3 +232,5 @@ int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
int btd_adapter_ssp_enabled(struct btd_adapter *adapter);
+
+GSList *adapter_get_devices(struct btd_adapter *adapter);
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC] battery: Add generic device battery interface
From: chen.ganir @ 2012-08-30 11:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1346325980-11411-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add the D-Bus API documentation for the new generic device battery
interface. This API provides generic access to peer devcice
batteries.
---
doc/battery-api.txt | 34 ++++++++++++++++++++++++++++++++++
doc/device-api.txt | 5 +++++
2 files changed, 39 insertions(+)
create mode 100644 doc/battery-api.txt
diff --git a/doc/battery-api.txt b/doc/battery-api.txt
new file mode 100644
index 0000000..da82024
--- /dev/null
+++ b/doc/battery-api.txt
@@ -0,0 +1,34 @@
+BlueZ D-Bus Battery API description
+****************************************
+
+ Texas Instruments, Inc. <chen.ganir@ti.com>
+
+Device Battery hierarchy
+=====================================
+
+Service org.bluez
+Interface org.bluez.Battery
+Object path [variable prefix]/{hci0,..}/dev_XX_XX_XX_XX_XX_XX/BATTYYYY
+YYYY is numeric value between 0 and 9999.
+
+Methods dict GetProperties()
+
+ Returns all properties for the interface. See the
+ Properties section for the available properties.
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties uint16 Level [readonly]
+
+ Battery level (0-100).
+
+ uint16 Description [readonly]
+
+ Battery description.
+
+ uint16 Namespace [readonly]
+
+ Battery Namespace.
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 1f0dc96..c98d539 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -179,3 +179,8 @@ Properties string Address [readonly]
Note that this property can exhibit false-positives
in the case of Bluetooth 2.1 (or newer) devices that
have disabled Extended Inquiry Response support.
+
+ array{object} Batteries [readonly]
+
+ List of device battery object paths that represents the available
+ batteries on the remote device.
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC] Add Generic Device Battery API
From: chen.ganir @ 2012-08-30 11:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
From: Chen Ganir <chen.ganir@ti.com>
This API proposal allows exposing peer device battery information to the D-Bus
clients. Profiles supporting peer device battery information (such as AVRCP,
LE Battery client) may use the internal API (next patch set) to register or
unregister batteries to be listed under the device object path. These batteries
have multiple read-only prpoerties that can be read by the D-Bus clients. In
addition, the new org.bluez.Battery interface allows sending PropertyChanged for
battery properties (such as Battery level).
Battery properties currently include the battery level, namespace and
description (currently used by the LE battery client). More properties can be
added or removed as we see fit in the future.
Comments on this patch will be appreciated.
Chen Ganir (1):
battery: Add generic device battery interface
doc/battery-api.txt | 34 ++++++++++++++++++++++++++++++++++
doc/device-api.txt | 5 +++++
2 files changed, 39 insertions(+)
create mode 100644 doc/battery-api.txt
--
1.7.9.5
^ permalink raw reply
* gnome-obex-send problem
From: Steffen Becker @ 2012-08-30 10:05 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
Hello,
i have two Scientific Linux 5.8 computers and a bluetooth 3.0+HS dongle
at each PC. The bluetooth devices are paired. I want to transmit data
files via bluetooth (more precisely: via HS) but it does not work:
On both PC's I added:
# sdptool add ftp
# sdptool add opush
then I tried:
# nautilus-sendto <data-file>
and choosed the remote device. But I got an error: "gnome-obex-send: the
remote device doesn't support object receiving".
Funny: When I shut down the remote device then i get the same error -.-
On top of that, I tried to start an obex server at the remote PC:
# gnome-obex-server
** (gnome-obex-server:18545): WARNING **: OBEX server register
error: -1
** (gnome-obex-server:18545): WARNING **: Unable to initialize OBEX
source
** (gnome-obex-server:18545): WARNING **: Couldn't initialise OBEX
listener
Does anyone know what to do?
Regards,
Steffen
^ permalink raw reply
* [PATCH BlueZ V7 3/5] AVRCP: Add browsing channel support
From: Vani-dineshbhai PATEL X @ 2012-08-30 9:50 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org, Luiz Augusto von Dentz
Cc: Vani-dineshbhai PATEL X, vani273, Joohi RASTOGI
>From 04eeee8851b3e7956f7f73dd48d91a789e25cdb5 Mon Sep 17 00:00:00 2001
From: Vani Patel <vani.patel@stericsson.com>
Date: Thu, 2 Aug 2012 16:42:14 +0530
Subject: [PATCH BlueZ V7 3/5] AVRCP: Add browsing channel support
Implements browsing channel creation and release.
---
audio/avctp.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 242 insertions(+), 32 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index 3bd021c..521fefa 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -41,6 +41,7 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/uuid.h>
+#include <bluetooth/l2cap.h>
#include <glib.h>
@@ -119,6 +120,7 @@ struct avctp_state_callback {
struct avctp_server {
bdaddr_t src;
GIOChannel *control_io;
+ GIOChannel *browsing_io;
GSList *sessions;
};
@@ -137,9 +139,12 @@ struct avctp {
int uinput;
GIOChannel *control_io;
+ GIOChannel *browsing_io;
guint control_io_id;
+ guint browsing_io_id;
uint16_t control_mtu;
+ uint16_t browsing_mtu;
uint8_t key_quirks[256];
GSList *handlers;
@@ -326,6 +331,17 @@ static void avctp_disconnected(struct avctp *session)
if (!session)
return;
+ if (session->browsing_io) {
+ g_io_channel_shutdown(session->browsing_io, TRUE, NULL);
+ g_io_channel_unref(session->browsing_io);
+ session->browsing_io = NULL;
+ }
+
+ if (session->browsing_io_id) {
+ g_source_remove(session->browsing_io_id);
+ session->browsing_io_id = 0;
+ }
+
if (session->control_io) {
g_io_channel_shutdown(session->control_io, TRUE, NULL);
g_io_channel_unref(session->control_io);
@@ -432,31 +448,77 @@ static void handle_response(struct avctp *session, struct avctp_header *avctp,
}
}
+static uint8_t *avctp_read_data(int *data_read, int length, GIOChannel *chan)
+{
+ uint8_t *buffer;
+ int sock;
+
+ buffer = g_new0(uint8_t, length);
+ sock = g_io_channel_unix_get_fd(chan);
+
+ *data_read = read(sock, buffer, length);
+ if (*data_read <= 0)
+ goto failed;
+
+ if (*data_read < AVCTP_HEADER_LENGTH) {
+ error("Too small AVCTP packet");
+ goto failed;
+ }
+ return buffer;
+
+failed:
+ return NULL;
+}
+
+static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avctp *session = data;
+ uint8_t *buf;
+ struct avctp_header *avctp;
+ int ret;
+
+ buf = avctp_read_data(&ret, session->browsing_mtu,
+ session->browsing_io);
+
+ if (buf == NULL)
+ goto failed;
+
+ if (!(cond & G_IO_IN))
+ goto failed;
+
+ avctp = (struct avctp_header *) buf;
+
+ if (avctp->packet_type != AVCTP_PACKET_SINGLE)
+ goto failed;
+
+ g_free(buf);
+ return TRUE;
+
+failed:
+ g_free(buf);
+ return FALSE;
+}
+
static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
struct avctp *session = data;
- uint8_t buf[1024], *operands, code, subunit;
+ uint8_t *buf, *operands, code, subunit;
struct avctp_header *avctp;
struct avc_header *avc;
int ret, packet_size, operand_count, sock;
struct avctp_pdu_handler *handler;
- if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+ buf = avctp_read_data(&ret, session->control_mtu, session->control_io);
+ if (buf == NULL)
goto failed;
- sock = g_io_channel_unix_get_fd(session->control_io);
-
- ret = read(sock, buf, sizeof(buf));
- if (ret <= 0)
- goto failed;
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+ goto failed;
- DBG("Got %d bytes of data for AVCTP session %p", ret, session);
+ sock = g_io_channel_unix_get_fd(session->control_io);
- if ((unsigned int) ret < sizeof(struct avctp_header)) {
- error("Too small AVCTP packet");
- goto failed;
- }
avctp = (struct avctp_header *) buf;
@@ -475,7 +537,8 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
ret -= sizeof(struct avc_header);
- operands = buf + sizeof(struct avctp_header) + sizeof(struct avc_header);
+ operands = buf + sizeof(struct avctp_header) +
+ sizeof(struct avc_header);
operand_count = ret;
DBG("AV/C %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
@@ -486,6 +549,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
if (avctp->cr == AVCTP_RESPONSE) {
handle_response(session, avctp, avc, operands, operand_count);
+ g_free(buf);
return TRUE;
}
@@ -526,9 +590,11 @@ done:
if (ret != packet_size)
goto failed;
+ g_free(buf);
return TRUE;
failed:
+ g_free(buf);
DBG("AVCTP session %p got disconnected", session);
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
return FALSE;
@@ -613,6 +679,47 @@ static void init_uinput(struct avctp *session)
DBG("AVRCP: uinput initialized for %s", address);
}
+static void avctp_connect_browsing_cb(GIOChannel *chan,
+ GError *err,
+ gpointer data)
+{
+ struct avctp *session = data;
+ char address[18];
+ uint16_t imtu;
+ GError *gerr = NULL;
+
+ if (err) {
+ error("Browsing: %s", err->message);
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ g_io_channel_unref(chan);
+ session->browsing_io = NULL;
+ return;
+ }
+
+ bt_io_get(chan, BT_IO_L2CAP, &gerr,
+ BT_IO_OPT_DEST, &address,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ g_io_channel_unref(chan);
+ session->browsing_io = NULL;
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ if (!session->browsing_io)
+ session->browsing_io = g_io_channel_ref(chan);
+
+ session->browsing_mtu = imtu;
+
+ session->browsing_io_id = g_io_add_watch(chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_browsing_cb, session);
+}
+
static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
{
struct avctp *session = data;
@@ -651,6 +758,32 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
(GIOFunc) session_cb, session);
}
+static void auth_browsing_cb(DBusError *derr, void *user_data)
+{
+ struct avctp *session = user_data;
+ GError *err = NULL;
+
+ if (session->browsing_io_id) {
+ g_source_remove(session->browsing_io_id);
+ session->browsing_io_id = 0;
+ }
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Browsing Access denied: %s", derr->message);
+ return;
+ }
+
+ if (!bt_io_accept(session->browsing_io, avctp_connect_browsing_cb,
+ session, NULL, &err)) {
+ error("Browsing bt_io_accept: %s", err->message);
+ if (session && session->browsing_io) {
+ g_io_channel_unref(session->browsing_io);
+ session->browsing_io = NULL;
+ }
+ g_error_free(err);
+ }
+}
+
static void auth_cb(DBusError *derr, void *user_data)
{
struct avctp *session = user_data;
@@ -729,6 +862,65 @@ static struct avctp *avctp_get_internal(const bdaddr_t *src,
return session;
}
+static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
+ struct audio_device *dev)
+{
+ if (session->control_io) {
+ error("Refusing unexpected connect from");
+ goto drop;
+ }
+
+ avctp_set_state(session, AVCTP_STATE_CONNECTING);
+ session->control_io = g_io_channel_ref(chan);
+
+ if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
+ auth_cb, session) < 0)
+ goto drop;
+
+ session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
+ G_IO_NVAL, session_cb, session);
+ return;
+
+drop:
+ if (!session || !session->control_io)
+ g_io_channel_shutdown(chan, TRUE, NULL);
+
+ if (session && session->control_io)
+ g_io_channel_unref(session->control_io);
+
+ if (session)
+ avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+}
+
+static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
+ struct audio_device *dev)
+{
+
+ if (!session->control_io) {
+ error("Browsing: Refusing unexpected connect from");
+ goto drop;
+ }
+
+ if (session->browsing_io) {
+ error("Browsing channel already exists");
+ goto drop;
+ }
+
+ session->browsing_io = g_io_channel_ref(chan);
+
+ if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
+ auth_browsing_cb, session) < 0)
+ goto drop;
+ return;
+
+drop:
+ if (!session || !session->control_io || !session->browsing_io)
+ g_io_channel_shutdown(chan, TRUE, NULL);
+
+ if (session && session->browsing_io)
+ g_io_channel_unref(session->browsing_io);
+}
+
static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
{
struct avctp *session;
@@ -736,11 +928,13 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
char address[18];
bdaddr_t src, dst;
GError *err = NULL;
+ uint16_t psm;
bt_io_get(chan, BT_IO_L2CAP, &err,
BT_IO_OPT_SOURCE_BDADDR, &src,
BT_IO_OPT_DEST_BDADDR, &dst,
BT_IO_OPT_DEST, address,
+ BT_IO_OPT_PSM, &psm,
BT_IO_OPT_INVALID);
if (err) {
error("%s", err->message);
@@ -771,40 +965,40 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
goto drop;
}
- if (session->control_io) {
- error("Refusing unexpected connect from %s", address);
- goto drop;
+ switch (psm) {
+ case AVCTP_CONTROL_PSM:
+ avctp_control_confirm(session, chan, dev);
+ break;
+ case AVCTP_BROWSING_PSM:
+ avctp_browsing_confirm(session, chan, dev);
+ break;
}
- avctp_set_state(session, AVCTP_STATE_CONNECTING);
- session->control_io = g_io_channel_ref(chan);
-
- if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
- auth_cb, session) < 0)
- goto drop;
-
- session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
- G_IO_NVAL, session_cb, session);
return;
drop:
- if (!session || !session->control_io)
- g_io_channel_shutdown(chan, TRUE, NULL);
- if (session)
+ if (session && session->browsing_io)
+ g_io_channel_unref(session->browsing_io);
+
+ if (session && session->control_io)
+ g_io_channel_unref(session->control_io);
+
+ if (session && psm == AVCTP_CONTROL_PSM)
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
}
-static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
+static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master,
+ uint8_t mode, uint16_t psm)
{
GError *err = NULL;
GIOChannel *io;
-
io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, src,
- BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
+ BT_IO_OPT_PSM, psm,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
BT_IO_OPT_MASTER, master,
+ BT_IO_OPT_MODE, mode,
BT_IO_OPT_INVALID);
if (!io) {
error("%s", err->message);
@@ -824,12 +1018,25 @@ int avctp_register(const bdaddr_t *src, gboolean master)
server = g_new0(struct avctp_server, 1);
- server->control_io = avctp_server_socket(src, master);
+ server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC,
+ AVCTP_CONTROL_PSM);
if (!server->control_io) {
g_free(server);
return -1;
}
+ server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM,
+ AVCTP_BROWSING_PSM);
+ if (!server->browsing_io) {
+ if (server->control_io) {
+ g_io_channel_shutdown(server->control_io, TRUE, NULL);
+ g_io_channel_unref(server->control_io);
+ server->control_io = NULL;
+ }
+ g_free(server);
+ return -1;
+ }
+
bacpy(&server->src, src);
servers = g_slist_append(servers, server);
@@ -861,6 +1068,9 @@ void avctp_unregister(const bdaddr_t *src)
avctp_disconnected(server->sessions->data);
servers = g_slist_remove(servers, server);
+ g_io_channel_shutdown(server->browsing_io, TRUE, NULL);
+ g_io_channel_unref(server->browsing_io);
+ server->browsing_io = NULL;
g_io_channel_shutdown(server->control_io, TRUE, NULL);
g_io_channel_unref(server->control_io);
--
1.7.5.4
Regards,
Vani
^ permalink raw reply related
* [PATCH] gatt: Delay D-Bus reply on char discovery
From: chen.ganir @ 2012-08-30 9:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
From: Chen Ganir <chen.ganir@ti.com>
Delay sending the D-Bus reply for the discover_characteristics
command. The D-Bus reply for characteristics is sent before all
the relevant characteristic information is gathered. This can
cause problems, when trying to get characteristic information too
soon. This patch moves the D-Bus reply to the end of the char
discovery process. Only after all descriptors are discovered and
read, the D-Bus reply is sent.
---
attrib/client.c | 163 +++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 116 insertions(+), 47 deletions(-)
diff --git a/attrib/client.c b/attrib/client.c
index bb6adf8..9b2103b 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -78,6 +78,11 @@ struct gatt_service {
struct query *query;
};
+struct characteristic_descriptor {
+ uint16_t handle;
+ bt_uuid_t uuid;
+};
+
struct characteristic {
struct gatt_service *gatt;
char *path;
@@ -90,6 +95,9 @@ struct characteristic {
struct format *format;
uint8_t *value;
size_t vlen;
+
+ GSList *descriptors;
+ uint16_t descriptor_count;
};
struct query_data {
@@ -116,6 +124,7 @@ static void characteristic_free(void *user_data)
g_free(chr->format);
g_free(chr->value);
g_free(chr->name);
+ g_slist_free_full(chr->descriptors, g_free);
g_free(chr);
}
@@ -263,6 +272,71 @@ static void update_watchers(gpointer data, gpointer user_data)
g_dbus_send_message(conn, msg);
}
+static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ GSList *l;
+
+ reply = dbus_message_new_method_return(msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+
+ for (l = chars; l; l = l->next) {
+ struct characteristic *chr = l->data;
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_OBJECT_PATH, &chr->path);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+
+static void check_chr_discovery_complete(struct gatt_service *gatt)
+{
+ DBusMessage *reply;
+ GSList *l;
+
+ for (l = gatt->chars; l; l = l->next) {
+ struct characteristic *chr = l->data;
+
+ if (chr->descriptor_count == 0xFFFF)
+ return;
+
+ if (chr->descriptor_count > g_slist_length(chr->descriptors))
+ return;
+ }
+
+ reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
+
+ dbus_message_unref(gatt->query->msg);
+ gatt->query->msg = NULL;
+
+ g_dbus_send_message(gatt->conn, reply);
+}
+
+static void add_descriptor(struct gatt_service *gatt,
+ struct characteristic *chr, uint16_t handle,
+ bt_uuid_t uuid)
+{
+ struct characteristic_descriptor *desc;
+
+ desc = g_new0(struct characteristic_descriptor, 1);
+
+ desc->handle = handle;
+ desc->uuid = uuid;
+
+ chr->descriptors = g_slist_append(chr->descriptors, desc);
+
+ check_chr_discovery_complete(gatt);
+}
+
static void events_handler(const uint8_t *pdu, uint16_t len,
gpointer user_data)
{
@@ -690,6 +764,7 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
struct query_data *current = user_data;
struct gatt_service *gatt = current->gatt;
struct characteristic *chr = current->chr;
+ bt_uuid_t uuid;
if (status == 0) {
@@ -720,6 +795,9 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
}
}
+ bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
+ add_descriptor(current->gatt, chr, current->handle, uuid);
+
query_list_remove(gatt, current);
g_free(current);
}
@@ -730,6 +808,7 @@ static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
struct query_data *current = user_data;
struct gatt_service *gatt = current->gatt;
struct characteristic *chr = current->chr;
+ bt_uuid_t uuid;
if (status != 0)
goto done;
@@ -746,6 +825,9 @@ static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
(void *) chr->format, sizeof(*chr->format));
done:
+ bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
+ add_descriptor(current->gatt, chr, current->handle, uuid);
+
query_list_remove(gatt, current);
g_free(current);
}
@@ -789,24 +871,33 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
{
struct query_data *current = user_data;
struct gatt_service *gatt = current->gatt;
+ struct characteristic *chr = current->chr;
struct att_data_list *list;
guint8 format;
int i;
- if (status != 0)
+ chr->descriptor_count = 0;
+
+ if (status != 0) {
+ check_chr_discovery_complete(gatt);
goto done;
+ }
DBG("Find Information Response received");
list = dec_find_info_resp(pdu, plen, &format);
- if (list == NULL)
+ if (list == NULL) {
+ check_chr_discovery_complete(gatt);
goto done;
+ }
+ chr->descriptor_count = list->num;
for (i = 0; i < list->num; i++) {
guint16 handle;
bt_uuid_t uuid;
uint8_t *info = list->data[i];
struct query_data *qfmt;
+ guint ret = 0;
handle = att_get_u16(info);
@@ -817,6 +908,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
* format" descriptors are used, and both have 16-bit
* UUIDs. Therefore there is no need to support format
* 0x02 yet. */
+ add_descriptor(gatt, chr, current->handle, uuid);
continue;
}
qfmt = g_new0(struct query_data, 1);
@@ -826,14 +918,17 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
query_list_append(gatt, qfmt);
- gatt_read_char(gatt->attrib, handle, 0, update_char_desc,
- qfmt);
+ ret = gatt_read_char(gatt->attrib, handle, 0,
+ update_char_desc, qfmt);
} else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
query_list_append(gatt, qfmt);
- gatt_read_char(gatt->attrib, handle, 0,
+ ret = gatt_read_char(gatt->attrib, handle, 0,
update_char_format, qfmt);
} else
g_free(qfmt);
+
+ if (ret == 0)
+ add_descriptor(gatt, chr, current->handle, uuid);
}
att_data_list_free(list);
@@ -848,53 +943,31 @@ static void update_all_chars(gpointer data, gpointer user_data)
struct characteristic *chr = data;
struct gatt_service *gatt = user_data;
- qdesc = g_new0(struct query_data, 1);
- qdesc->gatt = gatt;
- qdesc->chr = chr;
-
- query_list_append(gatt, qdesc);
-
- gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
- qdesc);
-
qvalue = g_new0(struct query_data, 1);
qvalue->gatt = gatt;
qvalue->chr = chr;
+ g_slist_free_full(chr->descriptors, g_free);
+ chr->descriptors = NULL;
+ chr->descriptor_count = 0xFFFF;
+
query_list_append(gatt, qvalue);
gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue);
-}
-
-static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars)
-{
- DBusMessage *reply;
- DBusMessageIter iter, array_iter;
- GSList *l;
-
- reply = dbus_message_new_method_return(msg);
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-
- for (l = chars; l; l = l->next) {
- struct characteristic *chr = l->data;
-
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_OBJECT_PATH, &chr->path);
- }
+ qdesc = g_new0(struct query_data, 1);
+ qdesc->gatt = gatt;
+ qdesc->chr = chr;
- dbus_message_iter_close_container(&iter, &array_iter);
+ query_list_append(gatt, qdesc);
- return reply;
+ gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
+ qdesc);
}
static void char_discovered_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
- DBusMessage *reply;
struct query_data *current = user_data;
struct gatt_service *gatt = current->gatt;
struct gatt_primary *prim = gatt->prim;
@@ -905,10 +978,13 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
if (status != 0) {
const char *str = att_ecode2str(status);
+ DBusMessage *reply = btd_error_failed(gatt->query->msg, str);
DBG("Discover all characteristics failed: %s", str);
- reply = btd_error_failed(gatt->query->msg, str);
- goto fail;
+ dbus_message_unref(gatt->query->msg);
+ g_dbus_send_message(gatt->conn, reply);
+
+ goto done;
}
for (l = characteristics; l; l = l->next) {
@@ -943,16 +1019,9 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
store_characteristics(&sba, &dba, bdaddr_type, prim->range.start,
gatt->chars);
-
g_slist_foreach(gatt->chars, update_all_chars, gatt);
- reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
-
-fail:
- dbus_message_unref(gatt->query->msg);
- gatt->query->msg = NULL;
-
- g_dbus_send_message(gatt->conn, reply);
+done:
query_list_remove(gatt, current);
g_free(current);
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH] Bluetooth: Remove unneeded zero init
From: Andrei Emeltchenko @ 2012-08-30 9:04 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
hdev is allocated with kzalloc so zero initialization is not needed.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/hci_core.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 36720f0..05bcea6 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -443,10 +443,8 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
static inline void hci_conn_hash_init(struct hci_dev *hdev)
{
struct hci_conn_hash *h = &hdev->conn_hash;
+
INIT_LIST_HEAD(&h->list);
- h->acl_num = 0;
- h->sco_num = 0;
- h->le_num = 0;
}
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ V6 5/5] AVRCP: Add handler for browsing pdu
From: Vani-dineshbhai PATEL X @ 2012-08-30 5:10 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <747C1E83C744F44E9ACFB89FAEEC2C7B23D4A4EACA@EXDCVYMBSTM005.EQ1STM.local>
>From c4bb95c4abf053bb727940c9c64a6fccb91234db Mon Sep 17 00:00:00 2001
From: Vani Patel <vani.patel@stericsson.com>
Date: Fri, 24 Aug 2012 16:36:00 +0530
Subject: [PATCH BlueZ V6 5/5] AVRCP: Add handler for browsing pdu
Implement generic handling of browsing
PDU IDs
---
audio/avctp.c | 27 ++++++++++++++++++--
audio/avrcp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 3 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index 6005962..bc656d7 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -480,13 +480,12 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
struct avctp *session = data;
- uint8_t *buf;
+ uint8_t *buf, *operands;
struct avctp_header *avctp;
- int ret;
+ int ret, packet_size, operand_count, sock;
buf = avctp_read_data(&ret, session->browsing_mtu,
session->browsing_io);
-
if (buf == NULL)
goto failed;
@@ -495,9 +494,31 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
avctp = (struct avctp_header *) buf;
+ DBG("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
+ "PID 0x%04X",
+ avctp->transaction, avctp->packet_type,
+ avctp->cr, avctp->ipid, ntohs(avctp->pid));
+
if (avctp->packet_type != AVCTP_PACKET_SINGLE)
goto failed;
+ operands = buf + AVCTP_HEADER_LENGTH;
+ ret -= AVCTP_HEADER_LENGTH;
+ operand_count = ret;
+
+ packet_size = AVCTP_HEADER_LENGTH;
+ avctp->cr = AVCTP_RESPONSE;
+ if (browsing_handler)
+ packet_size += browsing_handler->cb(session, avctp->transaction,
+ operands, operand_count, browsing_handler->user_data);
+
+ if (packet_size != 0) {
+ sock = g_io_channel_unix_get_fd(session->browsing_io);
+ ret = write(sock, buf, packet_size);
+ if (ret != packet_size)
+ goto failed;
+ }
+
g_free(buf);
return TRUE;
diff --git a/audio/avrcp.c b/audio/avrcp.c
index cd374a5..239ba25 100644
--- a/audio/avrcp.c
+++ b/audio/avrcp.c
@@ -94,6 +94,10 @@
#define AVRCP_ABORT_CONTINUING 0x41
#define AVRCP_SET_ABSOLUTE_VOLUME 0x50
+#define AVRCP_INVALID_BROWSING_PDU 0x00
+
+#define AVRCP_GENERAL_REJECT 0xA0
+
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
#define CAP_COMPANY_ID 0x02
#define CAP_EVENTS_SUPPORTED 0x03
@@ -141,6 +145,12 @@ struct avrcp_header {
#error "Unknown byte order"
#endif
+struct avrcp_browsing_header {
+ uint8_t browsing_pdu;
+ uint16_t param_len;
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
#define AVRCP_MTU (AVC_MTU - AVC_HEADER_LENGTH)
#define AVRCP_PDU_MTU (AVRCP_MTU - AVRCP_HEADER_LENGTH)
@@ -164,7 +174,9 @@ struct avrcp_player {
struct audio_device *dev;
unsigned int control_handler;
+ unsigned int browsing_handler;
uint16_t registered_events;
+ uint8_t transaction;
uint8_t transaction_events[AVRCP_EVENT_LAST + 1];
struct pending_pdu *pending_pdu;
@@ -1078,6 +1090,15 @@ static struct control_pdu_handler {
{ },
};
+static struct pdu_browsing_handler {
+ uint8_t browsing_pdu;
+ void (*func) (struct avrcp_player *player,
+ struct avrcp_browsing_header *pdu);
+ } browsing_handlers[] = {
+ { AVRCP_INVALID_BROWSING_PDU,
+ NULL },
+};
+
/* handle vendordep pdu inside an avctp packet */
static size_t handle_vendordep_pdu(struct avctp *session, uint8_t transaction,
uint8_t *code, uint8_t *subunit,
@@ -1137,6 +1158,49 @@ err_metadata:
return AVRCP_HEADER_LENGTH + 1;
}
+static size_t handle_browsing_pdu(struct avctp *session,
+ uint8_t transaction, uint8_t *operands,
+ size_t operand_count, void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct pdu_browsing_handler *b_handler;
+ struct avrcp_browsing_header *avrcp_browsing = (void *) operands;
+ uint8_t status;
+
+ operand_count += AVRCP_BROWSING_HEADER_LENGTH;
+
+ for (b_handler = browsing_handlers; b_handler; b_handler++) {
+ if (b_handler->browsing_pdu == AVRCP_INVALID_BROWSING_PDU) {
+ b_handler = NULL;
+ break;
+ }
+ if (b_handler->browsing_pdu == avrcp_browsing->browsing_pdu)
+ break;
+ }
+
+ if (!b_handler) {
+ avrcp_browsing->browsing_pdu = AVRCP_GENERAL_REJECT;
+ status = AVRCP_STATUS_INVALID_COMMAND;
+ goto err;
+ }
+
+ if (!b_handler->func) {
+ status = AVRCP_STATUS_INVALID_PARAM;
+ avrcp_browsing->param_len = htons(sizeof(status));
+ goto err;
+ }
+
+ player->transaction = transaction;
+ b_handler->func(player, avrcp_browsing);
+ return AVRCP_BROWSING_HEADER_LENGTH + ntohs(avrcp_browsing->param_len);
+
+err:
+ avrcp_browsing->param_len = htons(sizeof(status));
+ memcpy(&operands[AVRCP_BROWSING_HEADER_LENGTH], &status,
+ (sizeof(status)));
+ return AVRCP_BROWSING_HEADER_LENGTH + sizeof(status);
+}
+
size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands)
{
struct avrcp_header *pdu = (void *) operands;
@@ -1236,6 +1300,10 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
avctp_unregister_pdu_handler(player->control_handler);
player->control_handler = 0;
}
+ if (player->browsing_handler) {
+ avctp_unregister_browsing_pdu_handler();
+ player->browsing_handler = 0;
+ }
break;
case AVCTP_STATE_CONNECTING:
@@ -1247,6 +1315,12 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
AVC_OP_VENDORDEP,
handle_vendordep_pdu,
player);
+ if (!player->browsing_handler)
+ player->browsing_handler =
+ avctp_register_browsing_pdu_handler(
+ handle_browsing_pdu,
+ player);
+
break;
case AVCTP_STATE_CONNECTED:
rec = btd_device_get_record(dev->btd_dev, AVRCP_TARGET_UUID);
--
1.7.5.4
Regards,
Vani
^ permalink raw reply related
* [PATCH BlueZ V6 4/5] AVRCP: Register/Unregister Browsing handler
From: Vani-dineshbhai PATEL X @ 2012-08-30 5:09 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <747C1E83C744F44E9ACFB89FAEEC2C7B23D4A4EAC9@EXDCVYMBSTM005.EQ1STM.local>
>From b9980403f222d3f56ec1a0046e7bd13d06828976 Mon Sep 17 00:00:00 2001
From: Vani Patel <vani.patel@stericsson.com>
Date: Thu, 2 Aug 2012 17:05:03 +0530
Subject: [PATCH BlueZ V6 4/5] AVRCP: Register/Unregister Browsing handler
Add functions to register and unregister Browsing
handler
---
audio/avctp.c | 24 ++++++++++++++++++++++++
audio/avctp.h | 8 ++++++++
2 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index a159498..ed6efbe 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -157,6 +157,11 @@ struct avctp_pdu_handler {
unsigned int id;
};
+struct avctp_browsing_pdu_handler {
+ avctp_browsing_pdu_cb cb;
+ void *user_data;
+};
+
static struct {
const char *name;
uint8_t avc;
@@ -176,6 +181,7 @@ static GSList *callbacks = NULL;
static GSList *servers = NULL;
static GSList *control_handlers = NULL;
static uint8_t id = 0;
+static struct avctp_browsing_pdu_handler *browsing_handler = NULL;
static void auth_cb(DBusError *derr, void *user_data);
@@ -1252,6 +1258,18 @@ unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_control_pdu_cb cb,
return handler->id;
}
+unsigned int avctp_register_browsing_pdu_handler(avctp_browsing_pdu_cb cb,
+ void *user_data)
+{
+ unsigned int id = 0;
+
+ browsing_handler = g_new(struct avctp_browsing_pdu_handler, 1);
+ browsing_handler->cb = cb;
+ browsing_handler->user_data = user_data;
+
+ return ++id;
+}
+
gboolean avctp_unregister_pdu_handler(unsigned int id)
{
GSList *l;
@@ -1270,6 +1288,12 @@ gboolean avctp_unregister_pdu_handler(unsigned int id)
return FALSE;
}
+gboolean avctp_unregister_browsing_pdu_handler()
+{
+ g_free(browsing_handler);
+ return TRUE;
+}
+
struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst)
{
struct avctp *session;
diff --git a/audio/avctp.h b/audio/avctp.h
index b80e300..3e1dabe 100644
--- a/audio/avctp.h
+++ b/audio/avctp.h
@@ -83,6 +83,10 @@ typedef size_t (*avctp_control_pdu_cb) (struct avctp *session,
typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code,
uint8_t subunit, uint8_t *operands,
size_t operand_count, void *user_data);
+typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session,
+ uint8_t transaction,
+ uint8_t *operands, size_t operand_count,
+ void *user_data);
unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data);
gboolean avctp_remove_state_cb(unsigned int id);
@@ -98,6 +102,10 @@ unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_control_pdu_cb cb,
void *user_data);
gboolean avctp_unregister_pdu_handler(unsigned int id);
+unsigned int avctp_register_browsing_pdu_handler(avctp_browsing_pdu_cb cb,
+ void *user_data);
+
+gboolean avctp_unregister_browsing_pdu_handler();
int avctp_send_passthrough(struct avctp *session, uint8_t op);
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
uint8_t code, uint8_t subunit,
--
1.7.5.4
Regards,
Vani
^ permalink raw reply related
* FW: [PATCH BlueZ V6 3/5] AVRCP: Add browsing channel support
From: Vani-dineshbhai PATEL X @ 2012-08-30 5:09 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <747C1E83C744F44E9ACFB89FAEEC2C7B23D4A4EAC7@EXDCVYMBSTM005.EQ1STM.local>
>From 9fba02dd7351b78edc611445d2ed2cfd397b083f Mon Sep 17 00:00:00 2001
From: Vani Patel <vani.patel@stericsson.com>
Date: Thu, 2 Aug 2012 16:42:14 +0530
Subject: [PATCH BlueZ V6 3/5] AVRCP: Add browsing channel support
Implements browsing channel creation and release.
---
audio/avctp.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 240 insertions(+), 30 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index 3bd021c..8658b7a 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -41,6 +41,7 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/uuid.h>
+#include <bluetooth/l2cap.h>
#include <glib.h>
@@ -119,6 +120,7 @@ struct avctp_state_callback {
struct avctp_server {
bdaddr_t src;
GIOChannel *control_io;
+ GIOChannel *browsing_io;
GSList *sessions;
};
@@ -137,9 +139,12 @@ struct avctp {
int uinput;
GIOChannel *control_io;
+ GIOChannel *browsing_io;
guint control_io_id;
+ guint browsing_io_id;
uint16_t control_mtu;
+ uint16_t browsing_mtu;
uint8_t key_quirks[256];
GSList *handlers;
@@ -326,6 +331,17 @@ static void avctp_disconnected(struct avctp *session)
if (!session)
return;
+ if (session->browsing_io) {
+ g_io_channel_shutdown(session->browsing_io, TRUE, NULL);
+ g_io_channel_unref(session->browsing_io);
+ session->browsing_io = NULL;
+ }
+
+ if (session->browsing_io_id) {
+ g_source_remove(session->browsing_io_id);
+ session->browsing_io_id = 0;
+ }
+
if (session->control_io) {
g_io_channel_shutdown(session->control_io, TRUE, NULL);
g_io_channel_unref(session->control_io);
@@ -432,11 +448,63 @@ static void handle_response(struct avctp *session, struct avctp_header *avctp,
}
}
+static uint8_t *avctp_read_data(int *data_read, int length, GIOChannel *chan)
+{
+ uint8_t *buffer;
+ int sock;
+
+ buffer = g_new0(uint8_t, length);
+ sock = g_io_channel_unix_get_fd(chan);
+
+ *data_read = read(sock, buffer, length);
+ if (*data_read <= 0)
+ goto failed;
+
+ if (*data_read < AVCTP_HEADER_LENGTH) {
+ error("Too small AVCTP packet");
+ goto failed;
+ }
+ return buffer;
+
+failed:
+ return NULL;
+}
+
+static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avctp *session = data;
+ uint8_t *buf;
+ struct avctp_header *avctp;
+ int ret;
+
+ buf = avctp_read_data(&ret, session->browsing_mtu,
+ session->browsing_io);
+
+ if (buf == NULL)
+ goto failed;
+
+ if (!(cond & G_IO_IN))
+ goto failed;
+
+ avctp = (struct avctp_header *) buf;
+
+ if (avctp->packet_type != AVCTP_PACKET_SINGLE)
+ goto failed;
+
+ g_free(buf);
+ return TRUE;
+
+failed:
+ g_free(buf);
+ return FALSE;
+}
+
static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
struct avctp *session = data;
- uint8_t buf[1024], *operands, code, subunit;
+ uint8_t *buf, *operands, code, subunit;
struct avctp_header *avctp;
struct avc_header *avc;
int ret, packet_size, operand_count, sock;
@@ -445,18 +513,12 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
goto failed;
- sock = g_io_channel_unix_get_fd(session->control_io);
-
- ret = read(sock, buf, sizeof(buf));
- if (ret <= 0)
+ buf = avctp_read_data(&ret, session->control_mtu, session->control_io);
+ if (buf == NULL)
goto failed;
- DBG("Got %d bytes of data for AVCTP session %p", ret, session);
+ sock = g_io_channel_unix_get_fd(session->control_io);
- if ((unsigned int) ret < sizeof(struct avctp_header)) {
- error("Too small AVCTP packet");
- goto failed;
- }
avctp = (struct avctp_header *) buf;
@@ -475,7 +537,8 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
ret -= sizeof(struct avc_header);
- operands = buf + sizeof(struct avctp_header) + sizeof(struct avc_header);
+ operands = buf + sizeof(struct avctp_header) +
+ sizeof(struct avc_header);
operand_count = ret;
DBG("AV/C %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
@@ -486,6 +549,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
if (avctp->cr == AVCTP_RESPONSE) {
handle_response(session, avctp, avc, operands, operand_count);
+ g_free(buf);
return TRUE;
}
@@ -526,9 +590,11 @@ done:
if (ret != packet_size)
goto failed;
+ g_free(buf);
return TRUE;
failed:
+ g_free(buf);
DBG("AVCTP session %p got disconnected", session);
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
return FALSE;
@@ -613,6 +679,47 @@ static void init_uinput(struct avctp *session)
DBG("AVRCP: uinput initialized for %s", address);
}
+static void avctp_connect_browsing_cb(GIOChannel *chan,
+ GError *err,
+ gpointer data)
+{
+ struct avctp *session = data;
+ char address[18];
+ uint16_t imtu;
+ GError *gerr = NULL;
+
+ if (err) {
+ error("Browsing: %s", err->message);
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ g_io_channel_unref(chan);
+ session->browsing_io = NULL;
+ return;
+ }
+
+ bt_io_get(chan, BT_IO_L2CAP, &gerr,
+ BT_IO_OPT_DEST, &address,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ g_io_channel_unref(chan);
+ session->browsing_io = NULL;
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ if (!session->browsing_io)
+ session->browsing_io = g_io_channel_ref(chan);
+
+ session->browsing_mtu = imtu;
+
+ session->browsing_io_id = g_io_add_watch(chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_browsing_cb, session);
+}
+
static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
{
struct avctp *session = data;
@@ -651,6 +758,32 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
(GIOFunc) session_cb, session);
}
+static void auth_browsing_cb(DBusError *derr, void *user_data)
+{
+ struct avctp *session = user_data;
+ GError *err = NULL;
+
+ if (session->browsing_io_id) {
+ g_source_remove(session->browsing_io_id);
+ session->browsing_io_id = 0;
+ }
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Browsing Access denied: %s", derr->message);
+ return;
+ }
+
+ if (!bt_io_accept(session->browsing_io, avctp_connect_browsing_cb,
+ session, NULL, &err)) {
+ error("Browsing bt_io_accept: %s", err->message);
+ if (session && session->browsing_io) {
+ g_io_channel_unref(session->browsing_io);
+ session->browsing_io = NULL;
+ }
+ g_error_free(err);
+ }
+}
+
static void auth_cb(DBusError *derr, void *user_data)
{
struct avctp *session = user_data;
@@ -729,6 +862,65 @@ static struct avctp *avctp_get_internal(const bdaddr_t *src,
return session;
}
+static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
+ struct audio_device *dev)
+{
+ if (session->control_io) {
+ error("Refusing unexpected connect from");
+ goto drop;
+ }
+
+ avctp_set_state(session, AVCTP_STATE_CONNECTING);
+ session->control_io = g_io_channel_ref(chan);
+
+ if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
+ auth_cb, session) < 0)
+ goto drop;
+
+ session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
+ G_IO_NVAL, session_cb, session);
+ return;
+
+drop:
+ if (!session || !session->control_io)
+ g_io_channel_shutdown(chan, TRUE, NULL);
+
+ if (session && session->control_io)
+ g_io_channel_unref(session->control_io);
+
+ if (session)
+ avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+}
+
+static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
+ struct audio_device *dev)
+{
+
+ if (!session->control_io) {
+ error("Browsing: Refusing unexpected connect from");
+ goto drop;
+ }
+
+ if (session->browsing_io) {
+ error("Browsing channel already exists");
+ goto drop;
+ }
+
+ session->browsing_io = g_io_channel_ref(chan);
+
+ if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
+ auth_browsing_cb, session) < 0)
+ goto drop;
+ return;
+
+drop:
+ if (!session || !session->control_io || !session->browsing_io)
+ g_io_channel_shutdown(chan, TRUE, NULL);
+
+ if (session && session->browsing_io)
+ g_io_channel_unref(session->browsing_io);
+}
+
static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
{
struct avctp *session;
@@ -736,11 +928,13 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
char address[18];
bdaddr_t src, dst;
GError *err = NULL;
+ uint16_t psm;
bt_io_get(chan, BT_IO_L2CAP, &err,
BT_IO_OPT_SOURCE_BDADDR, &src,
BT_IO_OPT_DEST_BDADDR, &dst,
BT_IO_OPT_DEST, address,
+ BT_IO_OPT_PSM, &psm,
BT_IO_OPT_INVALID);
if (err) {
error("%s", err->message);
@@ -771,40 +965,40 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
goto drop;
}
- if (session->control_io) {
- error("Refusing unexpected connect from %s", address);
- goto drop;
+ switch (psm) {
+ case AVCTP_CONTROL_PSM:
+ avctp_control_confirm(session, chan, dev);
+ break;
+ case AVCTP_BROWSING_PSM:
+ avctp_browsing_confirm(session, chan, dev);
+ break;
}
- avctp_set_state(session, AVCTP_STATE_CONNECTING);
- session->control_io = g_io_channel_ref(chan);
-
- if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
- auth_cb, session) < 0)
- goto drop;
-
- session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
- G_IO_NVAL, session_cb, session);
return;
drop:
- if (!session || !session->control_io)
- g_io_channel_shutdown(chan, TRUE, NULL);
- if (session)
+ if (session && session->browsing_io)
+ g_io_channel_unref(session->browsing_io);
+
+ if (session && session->control_io)
+ g_io_channel_unref(session->control_io);
+
+ if (session && psm == AVCTP_CONTROL_PSM)
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
}
-static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
+static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master,
+ uint8_t mode, uint16_t psm)
{
GError *err = NULL;
GIOChannel *io;
-
io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, src,
- BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
+ BT_IO_OPT_PSM, psm,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
BT_IO_OPT_MASTER, master,
+ BT_IO_OPT_MODE, mode,
BT_IO_OPT_INVALID);
if (!io) {
error("%s", err->message);
@@ -824,12 +1018,25 @@ int avctp_register(const bdaddr_t *src, gboolean master)
server = g_new0(struct avctp_server, 1);
- server->control_io = avctp_server_socket(src, master);
+ server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC,
+ AVCTP_CONTROL_PSM);
if (!server->control_io) {
g_free(server);
return -1;
}
+ server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM,
+ AVCTP_BROWSING_PSM);
+ if (!server->browsing_io) {
+ if (server->control_io) {
+ g_io_channel_shutdown(server->control_io, TRUE, NULL);
+ g_io_channel_unref(server->control_io);
+ server->control_io = NULL;
+ }
+ g_free(server);
+ return -1;
+ }
+
bacpy(&server->src, src);
servers = g_slist_append(servers, server);
@@ -861,6 +1068,9 @@ void avctp_unregister(const bdaddr_t *src)
avctp_disconnected(server->sessions->data);
servers = g_slist_remove(servers, server);
+ g_io_channel_shutdown(server->browsing_io, TRUE, NULL);
+ g_io_channel_unref(server->browsing_io);
+ server->browsing_io = NULL;
g_io_channel_shutdown(server->control_io, TRUE, NULL);
g_io_channel_unref(server->control_io);
--
1.7.5.4
Regards,
Vani
^ permalink raw reply related
* [PATCH BlueZ V6 2/5] AVRCP: Rename variables used for control channel
From: Vani-dineshbhai PATEL X @ 2012-08-30 5:09 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <747C1E83C744F44E9ACFB89FAEEC2C7B23D4A4EAC4@EXDCVYMBSTM005.EQ1STM.local>
>From 7932a19fe620ad8ecaa8377ac376b4e428e2ee90 Mon Sep 17 00:00:00 2001
From: Vani Patel <vani.patel@stericsson.com>
Date: Tue, 14 Aug 2012 13:23:23 +0530
Subject: [PATCH BlueZ V6 2/5] AVRCP: Rename variables used for control channel
to improve redability
Prefix "control" is added to variables used for
control channel. This will improve redability
when Browsing channel is implemented
---
audio/avctp.c | 83 +++++++++++++++++++++++++++++----------------------------
audio/avctp.h | 5 ++-
audio/avrcp.c | 54 ++++++++++++++++++------------------
3 files changed, 72 insertions(+), 70 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index a20dba9..3bd021c 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -118,7 +118,7 @@ struct avctp_state_callback {
struct avctp_server {
bdaddr_t src;
- GIOChannel *io;
+ GIOChannel *control_io;
GSList *sessions;
};
@@ -136,10 +136,10 @@ struct avctp {
int uinput;
- GIOChannel *io;
- guint io_id;
+ GIOChannel *control_io;
+ guint control_io_id;
- uint16_t mtu;
+ uint16_t control_mtu;
uint8_t key_quirks[256];
GSList *handlers;
@@ -147,7 +147,7 @@ struct avctp {
struct avctp_pdu_handler {
uint8_t opcode;
- avctp_pdu_cb cb;
+ avctp_control_pdu_cb cb;
void *user_data;
unsigned int id;
};
@@ -169,7 +169,7 @@ static struct {
static GSList *callbacks = NULL;
static GSList *servers = NULL;
-static GSList *handlers = NULL;
+static GSList *control_handlers = NULL;
static uint8_t id = 0;
static void auth_cb(DBusError *derr, void *user_data);
@@ -326,15 +326,15 @@ static void avctp_disconnected(struct avctp *session)
if (!session)
return;
- if (session->io) {
- g_io_channel_shutdown(session->io, TRUE, NULL);
- g_io_channel_unref(session->io);
- session->io = NULL;
+ if (session->control_io) {
+ g_io_channel_shutdown(session->control_io, TRUE, NULL);
+ g_io_channel_unref(session->control_io);
+ session->control_io = NULL;
}
- if (session->io_id) {
- g_source_remove(session->io_id);
- session->io_id = 0;
+ if (session->control_io_id) {
+ g_source_remove(session->control_io_id);
+ session->control_io_id = 0;
if (session->state == AVCTP_STATE_CONNECTING) {
struct audio_device *dev;
@@ -445,7 +445,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
goto failed;
- sock = g_io_channel_unix_get_fd(session->io);
+ sock = g_io_channel_unix_get_fd(session->control_io);
ret = read(sock, buf, sizeof(buf));
if (ret <= 0)
@@ -503,7 +503,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
goto done;
}
- handler = find_handler(handlers, avc->opcode);
+ handler = find_handler(control_handlers, avc->opcode);
if (!handler) {
DBG("handler not found for 0x%02x", avc->opcode);
packet_size += avrcp_handle_vendor_reject(&code, operands);
@@ -639,14 +639,14 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
DBG("AVCTP: connected to %s", address);
- if (!session->io)
- session->io = g_io_channel_ref(chan);
+ if (!session->control_io)
+ session->control_io = g_io_channel_ref(chan);
init_uinput(session);
avctp_set_state(session, AVCTP_STATE_CONNECTED);
- session->mtu = imtu;
- session->io_id = g_io_add_watch(chan,
+ session->control_mtu = imtu;
+ session->control_io_id = g_io_add_watch(chan,
G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc) session_cb, session);
}
@@ -656,9 +656,9 @@ static void auth_cb(DBusError *derr, void *user_data)
struct avctp *session = user_data;
GError *err = NULL;
- if (session->io_id) {
- g_source_remove(session->io_id);
- session->io_id = 0;
+ if (session->control_io_id) {
+ g_source_remove(session->control_io_id);
+ session->control_io_id = 0;
}
if (derr && dbus_error_is_set(derr)) {
@@ -667,7 +667,7 @@ static void auth_cb(DBusError *derr, void *user_data)
return;
}
- if (!bt_io_accept(session->io, avctp_connect_cb, session,
+ if (!bt_io_accept(session->control_io, avctp_connect_cb, session,
NULL, &err)) {
error("bt_io_accept: %s", err->message);
g_error_free(err);
@@ -771,24 +771,24 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
goto drop;
}
- if (session->io) {
+ if (session->control_io) {
error("Refusing unexpected connect from %s", address);
goto drop;
}
avctp_set_state(session, AVCTP_STATE_CONNECTING);
- session->io = g_io_channel_ref(chan);
+ session->control_io = g_io_channel_ref(chan);
if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
auth_cb, session) < 0)
goto drop;
- session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- session_cb, session);
+ session->control_io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
+ G_IO_NVAL, session_cb, session);
return;
drop:
- if (!session || !session->io)
+ if (!session || !session->control_io)
g_io_channel_shutdown(chan, TRUE, NULL);
if (session)
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
@@ -824,8 +824,8 @@ int avctp_register(const bdaddr_t *src, gboolean master)
server = g_new0(struct avctp_server, 1);
- server->io = avctp_server_socket(src, master);
- if (!server->io) {
+ server->control_io = avctp_server_socket(src, master);
+ if (!server->control_io) {
g_free(server);
return -1;
}
@@ -862,8 +862,8 @@ void avctp_unregister(const bdaddr_t *src)
servers = g_slist_remove(servers, server);
- g_io_channel_shutdown(server->io, TRUE, NULL);
- g_io_channel_unref(server->io);
+ g_io_channel_shutdown(server->control_io, TRUE, NULL);
+ g_io_channel_unref(server->control_io);
g_free(server);
if (servers)
@@ -910,7 +910,7 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op)
operands[0] = op & 0x7f;
operands[1] = 0;
- sk = g_io_channel_unix_get_fd(session->io);
+ sk = g_io_channel_unix_get_fd(session->control_io);
if (write(sk, buf, sizeof(buf)) < 0)
return -errno;
@@ -939,7 +939,7 @@ static int avctp_send(struct avctp *session, uint8_t transaction, uint8_t cr,
if (session->state != AVCTP_STATE_CONNECTED)
return -ENOTCONN;
- sk = g_io_channel_unix_get_fd(session->io);
+ sk = g_io_channel_unix_get_fd(session->control_io);
memset(buf, 0, sizeof(buf));
@@ -1034,13 +1034,13 @@ gboolean avctp_remove_state_cb(unsigned int id)
return FALSE;
}
-unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb,
+unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_control_pdu_cb cb,
void *user_data)
{
struct avctp_pdu_handler *handler;
static unsigned int id = 0;
- handler = find_handler(handlers, opcode);
+ handler = find_handler(control_handlers, opcode);
if (handler)
return 0;
@@ -1050,7 +1050,7 @@ unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb,
handler->user_data = user_data;
handler->id = ++id;
- handlers = g_slist_append(handlers, handler);
+ control_handlers = g_slist_append(control_handlers, handler);
return handler->id;
}
@@ -1059,11 +1059,12 @@ gboolean avctp_unregister_pdu_handler(unsigned int id)
{
GSList *l;
- for (l = handlers; l != NULL; l = l->next) {
+ for (l = control_handlers; l != NULL; l = l->next) {
struct avctp_pdu_handler *handler = l->data;
if (handler->id == id) {
- handlers = g_slist_remove(handlers, handler);
+ control_handlers = g_slist_remove(control_handlers,
+ handler);
g_free(handler);
return TRUE;
}
@@ -1099,14 +1100,14 @@ struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst)
return NULL;
}
- session->io = io;
+ session->control_io = io;
return session;
}
void avctp_disconnect(struct avctp *session)
{
- if (!session->io)
+ if (!session->control_io)
return;
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
diff --git a/audio/avctp.h b/audio/avctp.h
index 34b0c1c..b80e300 100644
--- a/audio/avctp.h
+++ b/audio/avctp.h
@@ -75,7 +75,8 @@ typedef void (*avctp_state_cb) (struct audio_device *dev,
avctp_state_t new_state,
void *user_data);
-typedef size_t (*avctp_pdu_cb) (struct avctp *session, uint8_t transaction,
+typedef size_t (*avctp_control_pdu_cb) (struct avctp *session,
+ uint8_t transaction,
uint8_t *code, uint8_t *subunit,
uint8_t *operands, size_t operand_count,
void *user_data);
@@ -93,7 +94,7 @@ struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst);
struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst);
void avctp_disconnect(struct avctp *session);
-unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb,
+unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_control_pdu_cb cb,
void *user_data);
gboolean avctp_unregister_pdu_handler(unsigned int id);
diff --git a/audio/avrcp.c b/audio/avrcp.c
index c7c8ae6..cd374a5 100644
--- a/audio/avrcp.c
+++ b/audio/avrcp.c
@@ -163,7 +163,7 @@ struct avrcp_player {
struct avctp *session;
struct audio_device *dev;
- unsigned int handler;
+ unsigned int control_handler;
uint16_t registered_events;
uint8_t transaction_events[AVRCP_EVENT_LAST + 1];
struct pending_pdu *pending_pdu;
@@ -256,9 +256,9 @@ static sdp_record_t *avrcp_tg_record(void)
sdp_list_t *svclass_id, *pfseq, *apseq, *root, *apseq_browsing;
uuid_t root_uuid, l2cap, avctp, avrtg;
sdp_profile_desc_t profile[1];
- sdp_list_t *aproto, *proto[2];
+ sdp_list_t *aproto_control, *proto_control[2];
sdp_record_t *record;
- sdp_data_t *psm, *version, *features, *psm_browsing;
+ sdp_data_t *psm_control, *version, *features, *psm_browsing;
sdp_list_t *aproto_browsing, *proto_browsing[2] = {0};
uint16_t lp = AVCTP_CONTROL_PSM;
uint16_t lp_browsing = AVCTP_BROWSING_PSM;
@@ -285,19 +285,19 @@ static sdp_record_t *avrcp_tg_record(void)
/* Protocol Descriptor List */
sdp_uuid16_create(&l2cap, L2CAP_UUID);
- proto[0] = sdp_list_append(0, &l2cap);
- psm = sdp_data_alloc(SDP_UINT16, &lp);
- proto[0] = sdp_list_append(proto[0], psm);
- apseq = sdp_list_append(0, proto[0]);
+ proto_control[0] = sdp_list_append(0, &l2cap);
+ psm_control = sdp_data_alloc(SDP_UINT16, &lp);
+ proto_control[0] = sdp_list_append(proto_control[0], psm_control);
+ apseq = sdp_list_append(0, proto_control[0]);
sdp_uuid16_create(&avctp, AVCTP_UUID);
- proto[1] = sdp_list_append(0, &avctp);
+ proto_control[1] = sdp_list_append(0, &avctp);
version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
- proto[1] = sdp_list_append(proto[1], version);
- apseq = sdp_list_append(apseq, proto[1]);
+ proto_control[1] = sdp_list_append(proto_control[1], version);
+ apseq = sdp_list_append(apseq, proto_control[1]);
- aproto = sdp_list_append(0, apseq);
- sdp_set_access_protos(record, aproto);
+ aproto_control = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto_control);
proto_browsing[0] = sdp_list_append(0, &l2cap);
psm_browsing = sdp_data_alloc(SDP_UINT16, &lp_browsing);
proto_browsing[0] = sdp_list_append(proto_browsing[0], psm_browsing);
@@ -326,12 +326,12 @@ static sdp_record_t *avrcp_tg_record(void)
sdp_list_free(proto_browsing[1], 0);
sdp_list_free(apseq_browsing, 0);
sdp_list_free(aproto_browsing, 0);
- free(psm);
+ free(psm_control);
free(version);
- sdp_list_free(proto[0], 0);
- sdp_list_free(proto[1], 0);
+ sdp_list_free(proto_control[0], 0);
+ sdp_list_free(proto_control[1], 0);
sdp_list_free(apseq, 0);
- sdp_list_free(aproto, 0);
+ sdp_list_free(aproto_control, 0);
sdp_list_free(pfseq, 0);
sdp_list_free(root, 0);
sdp_list_free(svclass_id, 0);
@@ -1040,13 +1040,13 @@ err:
return AVC_CTYPE_REJECTED;
}
-static struct pdu_handler {
+static struct control_pdu_handler {
uint8_t pdu_id;
uint8_t code;
uint8_t (*func) (struct avrcp_player *player,
struct avrcp_header *pdu,
uint8_t transaction);
-} handlers[] = {
+} control_handlers[] = {
{ AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
avrcp_handle_get_capabilities },
{ AVRCP_LIST_PLAYER_ATTRIBUTES, AVC_CTYPE_STATUS,
@@ -1085,7 +1085,7 @@ static size_t handle_vendordep_pdu(struct avctp *session, uint8_t transaction,
void *user_data)
{
struct avrcp_player *player = user_data;
- struct pdu_handler *handler;
+ struct control_pdu_handler *handler;
struct avrcp_header *pdu = (void *) operands;
uint32_t company_id = get_company_id(pdu->company_id);
@@ -1105,7 +1105,7 @@ static size_t handle_vendordep_pdu(struct avctp *session, uint8_t transaction,
goto err_metadata;
}
- for (handler = handlers; handler; handler++) {
+ for (handler = control_handlers; handler; handler++) {
if (handler->pdu_id == pdu->pdu_id)
break;
}
@@ -1232,9 +1232,9 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
player->dev = NULL;
player->registered_events = 0;
- if (player->handler) {
- avctp_unregister_pdu_handler(player->handler);
- player->handler = 0;
+ if (player->control_handler) {
+ avctp_unregister_pdu_handler(player->control_handler);
+ player->control_handler = 0;
}
break;
@@ -1242,8 +1242,8 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
player->session = avctp_connect(&dev->src, &dev->dst);
player->dev = dev;
- if (!player->handler)
- player->handler = avctp_register_pdu_handler(
+ if (!player->control_handler)
+ player->control_handler = avctp_register_pdu_handler(
AVC_OP_VENDORDEP,
handle_vendordep_pdu,
player);
@@ -1361,8 +1361,8 @@ static void player_destroy(gpointer data)
player_abort_pending_pdu(player);
- if (player->handler)
- avctp_unregister_pdu_handler(player->handler);
+ if (player->control_handler)
+ avctp_unregister_pdu_handler(player->control_handler);
g_free(player);
}
--
1.7.5.4
Regards,
Vani
^ permalink raw reply related
* [PATCH BlueZ V6 1/5] AVRCP: Add TG Record to support AVRCP Browsing
From: Vani-dineshbhai PATEL X @ 2012-08-30 5:08 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <747C1E83C744F44E9ACFB89FAEEC2C7B23D4A4EAC2@EXDCVYMBSTM005.EQ1STM.local>
>From 7e32aecb2b13c6398108932e98fdd68faf9315d8 Mon Sep 17 00:00:00 2001
From: Vani Patel <vani.patel@stericsson.com>
Date: Tue, 5 Jun 2012 13:44:30 +0530
Subject: [PATCH BlueZ V6 1/5] AVRCP: Add TG Record to support AVRCP Browsing
Adds SDP record to support browsing
---
audio/avctp.c | 4 ++--
audio/avctp.h | 3 ++-
audio/avrcp.c | 28 ++++++++++++++++++++++++----
3 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/audio/avctp.c b/audio/avctp.c
index 074eabd..a20dba9 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -802,7 +802,7 @@ static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, src,
- BT_IO_OPT_PSM, AVCTP_PSM,
+ BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
BT_IO_OPT_MASTER, master,
BT_IO_OPT_INVALID);
@@ -1090,7 +1090,7 @@ struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst)
io = bt_io_connect(BT_IO_L2CAP, avctp_connect_cb, session, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
BT_IO_OPT_DEST_BDADDR, &session->dst,
- BT_IO_OPT_PSM, AVCTP_PSM,
+ BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
BT_IO_OPT_INVALID);
if (err) {
avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
diff --git a/audio/avctp.h b/audio/avctp.h
index d0cbd97..34b0c1c 100644
--- a/audio/avctp.h
+++ b/audio/avctp.h
@@ -22,7 +22,8 @@
*
*/
-#define AVCTP_PSM 23
+#define AVCTP_CONTROL_PSM 23
+#define AVCTP_BROWSING_PSM 27
#define AVC_MTU 512
#define AVC_HEADER_LENGTH 3
diff --git a/audio/avrcp.c b/audio/avrcp.c
index d925365..c7c8ae6 100644
--- a/audio/avrcp.c
+++ b/audio/avrcp.c
@@ -105,6 +105,7 @@
#define AVRCP_FEATURE_CATEGORY_3 0x0004
#define AVRCP_FEATURE_CATEGORY_4 0x0008
#define AVRCP_FEATURE_PLAYER_SETTINGS 0x0010
+#define AVRCP_FEATURE_BROWSING 0x0040
#define AVRCP_BATTERY_STATUS_NORMAL 0
#define AVRCP_BATTERY_STATUS_WARNING 1
@@ -190,7 +191,7 @@ static sdp_record_t *avrcp_ct_record(void)
sdp_list_t *aproto, *proto[2];
sdp_record_t *record;
sdp_data_t *psm, *version, *features;
- uint16_t lp = AVCTP_PSM;
+ uint16_t lp = AVCTP_CONTROL_PSM;
uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103;
uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
AVRCP_FEATURE_CATEGORY_2 |
@@ -252,18 +253,21 @@ static sdp_record_t *avrcp_ct_record(void)
static sdp_record_t *avrcp_tg_record(void)
{
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root, *apseq_browsing;
uuid_t root_uuid, l2cap, avctp, avrtg;
sdp_profile_desc_t profile[1];
sdp_list_t *aproto, *proto[2];
sdp_record_t *record;
- sdp_data_t *psm, *version, *features;
- uint16_t lp = AVCTP_PSM;
+ sdp_data_t *psm, *version, *features, *psm_browsing;
+ sdp_list_t *aproto_browsing, *proto_browsing[2] = {0};
+ uint16_t lp = AVCTP_CONTROL_PSM;
+ uint16_t lp_browsing = AVCTP_BROWSING_PSM;
uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
AVRCP_FEATURE_CATEGORY_2 |
AVRCP_FEATURE_CATEGORY_3 |
AVRCP_FEATURE_CATEGORY_4 |
+ AVRCP_FEATURE_BROWSING |
AVRCP_FEATURE_PLAYER_SETTINGS );
record = sdp_record_alloc();
@@ -294,6 +298,17 @@ static sdp_record_t *avrcp_tg_record(void)
aproto = sdp_list_append(0, apseq);
sdp_set_access_protos(record, aproto);
+ proto_browsing[0] = sdp_list_append(0, &l2cap);
+ psm_browsing = sdp_data_alloc(SDP_UINT16, &lp_browsing);
+ proto_browsing[0] = sdp_list_append(proto_browsing[0], psm_browsing);
+ apseq_browsing = sdp_list_append(0, proto_browsing[0]);
+
+ proto_browsing[1] = sdp_list_append(0, &avctp);
+ proto_browsing[1] = sdp_list_append(proto_browsing[1], version);
+ apseq_browsing = sdp_list_append(apseq_browsing, proto_browsing[1]);
+
+ aproto_browsing = sdp_list_append(0, apseq_browsing);
+ sdp_set_add_access_protos(record, aproto_browsing);
/* Bluetooth Profile Descriptor List */
sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
@@ -306,6 +321,11 @@ static sdp_record_t *avrcp_tg_record(void)
sdp_set_info_attr(record, "AVRCP TG", 0, 0);
+ free(psm_browsing);
+ sdp_list_free(proto_browsing[0], 0);
+ sdp_list_free(proto_browsing[1], 0);
+ sdp_list_free(apseq_browsing, 0);
+ sdp_list_free(aproto_browsing, 0);
free(psm);
free(version);
sdp_list_free(proto[0], 0);
--
1.7.5.4
Regards,
Vani
^ permalink raw reply related
* [PATCH BlueZ v1 6/6] hog: Add writting Control Point
From: Claudio Takahasi @ 2012-08-29 20:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1346273590-16693-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds GATT write without response operation when suspending
or resuming.
---
profiles/input/hog_device.c | 27 ++++++++++++++++++++++++++-
profiles/input/hog_device.h | 1 +
profiles/input/hog_manager.c | 16 ++++++++++++++++
3 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/profiles/input/hog_device.c b/profiles/input/hog_device.c
index af21f24..369afd2 100644
--- a/profiles/input/hog_device.c
+++ b/profiles/input/hog_device.c
@@ -56,6 +56,7 @@
#define HOG_REPORT_MAP_UUID 0x2A4B
#define HOG_REPORT_UUID 0x2A4D
#define HOG_PROTO_MODE_UUID 0x2A4E
+#define HOG_CONTROL_POINT_UUID 0x2A4C
#define HOG_REPORT_TYPE_INPUT 1
#define HOG_REPORT_TYPE_OUTPUT 2
@@ -83,6 +84,7 @@ struct hog_device {
uint16_t bcdhid;
uint8_t bcountrycode;
uint16_t proto_mode_handle;
+ uint16_t ctrlpt_handle;
uint8_t flags;
};
@@ -438,7 +440,8 @@ static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
{
struct hog_device *hogdev = user_data;
- bt_uuid_t report_uuid, report_map_uuid, info_uuid, proto_mode_uuid;
+ bt_uuid_t report_uuid, report_map_uuid, info_uuid, proto_mode_uuid,
+ ctrlpt_uuid;
struct report *report;
GSList *l;
uint16_t info_handle = 0, proto_mode_handle = 0;
@@ -453,6 +456,7 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
bt_uuid16_create(&info_uuid, HOG_INFO_UUID);
bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
+ bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
for (l = chars; l; l = g_slist_next(l)) {
struct gatt_char *chr, *next;
@@ -481,6 +485,8 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
info_handle = chr->value_handle;
else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
proto_mode_handle = chr->value_handle;
+ else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
+ hogdev->ctrlpt_handle = chr->value_handle;
}
if (proto_mode_handle) {
@@ -764,3 +770,22 @@ int hog_device_unregister(struct hog_device *hogdev)
return 0;
}
+
+int hog_device_set_control_point(struct hog_device *hogdev, gboolean suspend)
+{
+ uint8_t value = suspend ? 0x00 : 0x01;
+
+ if (hogdev->attrib == NULL)
+ return -ENOTCONN;
+
+ DBG("%s HID Control Point: %s", hogdev->path, suspend ?
+ "Suspend" : "Exit Suspend");
+
+ if (hogdev->ctrlpt_handle == 0)
+ return -ENOTSUP;
+
+ gatt_write_char(hogdev->attrib, hogdev->ctrlpt_handle, &value,
+ sizeof(value), NULL, NULL);
+
+ return 0;
+}
diff --git a/profiles/input/hog_device.h b/profiles/input/hog_device.h
index efb7b4f..03f1c90 100644
--- a/profiles/input/hog_device.h
+++ b/profiles/input/hog_device.h
@@ -31,3 +31,4 @@ struct hog_device *hog_device_register(struct btd_device *device,
const char *path, int *perr);
int hog_device_unregister(struct hog_device *hogdev);
struct hog_device *hog_device_find(GSList *list, const char *path);
+int hog_device_set_control_point(struct hog_device *hogdev, gboolean suspend);
diff --git a/profiles/input/hog_manager.c b/profiles/input/hog_manager.c
index c83c345..97f2519 100644
--- a/profiles/input/hog_manager.c
+++ b/profiles/input/hog_manager.c
@@ -41,14 +41,30 @@
static gboolean suspend_supported = FALSE;
static GSList *devices = NULL;
+static void set_suspend(gpointer data, gpointer user_data)
+{
+ struct hog_device *hogdev = data;
+ gboolean suspend = GPOINTER_TO_INT(user_data);
+
+ hog_device_set_control_point(hogdev, suspend);
+}
+
static void suspend_callback(void)
{
+ gboolean suspend = TRUE;
+
DBG("Suspending ...");
+
+ g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
}
static void resume_callback(void)
{
+ gboolean suspend = FALSE;
+
DBG("Resuming ...");
+
+ g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
}
static int hog_device_probe(struct btd_device *device, GSList *uuids)
--
1.7.12
^ permalink raw reply related
* [PATCH BlueZ v1 5/6] hog: Move HoG device list to manager
From: Claudio Takahasi @ 2012-08-29 20:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1346273590-16693-1-git-send-email-claudio.takahasi@openbossa.org>
This patch moves the HoG device list from hog_device.c to hog_manager.c
in order to be possible to easily notify suspend/resume events to each
created device.
---
profiles/input/hog_device.c | 46 +++++++++++++++++++++-----------------------
profiles/input/hog_device.h | 8 ++++++--
profiles/input/hog_manager.c | 22 +++++++++++++++++++--
3 files changed, 48 insertions(+), 28 deletions(-)
diff --git a/profiles/input/hog_device.c b/profiles/input/hog_device.c
index 000f173..af21f24 100644
--- a/profiles/input/hog_device.c
+++ b/profiles/input/hog_device.c
@@ -93,8 +93,6 @@ struct report {
struct hog_device *hogdev;
};
-static GSList *devices = NULL;
-
static gint report_handle_cmp(gconstpointer a, gconstpointer b)
{
const struct report *report = a;
@@ -628,7 +626,7 @@ static void attio_disconnected_cb(gpointer user_data)
hogdev->attrib = NULL;
}
-static struct hog_device *find_device_by_path(GSList *list, const char *path)
+struct hog_device *hog_device_find(GSList *list, const char *path)
{
for (; list; list = list->next) {
struct hog_device *hogdev = list->data;
@@ -690,31 +688,33 @@ static void hog_device_free(struct hog_device *hogdev)
g_free(hogdev);
}
-int hog_device_register(struct btd_device *device, const char *path)
+struct hog_device *hog_device_register(struct btd_device *device,
+ const char *path, int *perr)
{
- struct hog_device *hogdev;
struct gatt_primary *prim;
+ struct hog_device *hogdev;
GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_NVAL;
GIOChannel *io;
-
- hogdev = find_device_by_path(devices, path);
- if (hogdev)
- return -EALREADY;
+ int err;
prim = load_hog_primary(device);
- if (!prim)
- return -EINVAL;
+ if (!prim) {
+ err = -EINVAL;
+ goto failed;
+ }
hogdev = hog_device_new(device, path);
- if (!hogdev)
- return -ENOMEM;
+ if (!hogdev) {
+ err = -ENOMEM;
+ goto failed;
+ }
hogdev->uhid_fd = open(UHID_DEVICE_FILE, O_RDWR | O_CLOEXEC);
if (hogdev->uhid_fd < 0) {
- int err = -errno;
+ err = -errno;
error("Failed to open uHID device: %s", strerror(-err));
hog_device_free(hogdev);
- return err;
+ goto failed;
}
io = g_io_channel_unix_new(hogdev->uhid_fd);
@@ -732,20 +732,19 @@ int hog_device_register(struct btd_device *device, const char *path)
device_set_auto_connect(device, TRUE);
- devices = g_slist_append(devices, hogdev);
+ return hogdev;
- return 0;
+failed:
+ if (perr)
+ *perr = err;
+
+ return NULL;
}
-int hog_device_unregister(const char *path)
+int hog_device_unregister(struct hog_device *hogdev)
{
- struct hog_device *hogdev;
struct uhid_event ev;
- hogdev = find_device_by_path(devices, path);
- if (hogdev == NULL)
- return -EINVAL;
-
btd_device_remove_attio_callback(hogdev->device, hogdev->attioid);
if (hogdev->uhid_watch_id) {
@@ -761,7 +760,6 @@ int hog_device_unregister(const char *path)
close(hogdev->uhid_fd);
hogdev->uhid_fd = -1;
- devices = g_slist_remove(devices, hogdev);
hog_device_free(hogdev);
return 0;
diff --git a/profiles/input/hog_device.h b/profiles/input/hog_device.h
index 597dc7c..efb7b4f 100644
--- a/profiles/input/hog_device.h
+++ b/profiles/input/hog_device.h
@@ -25,5 +25,9 @@
#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
-int hog_device_register(struct btd_device *device, const char *path);
-int hog_device_unregister(const char *path);
+struct hog_device;
+
+struct hog_device *hog_device_register(struct btd_device *device,
+ const char *path, int *perr);
+int hog_device_unregister(struct hog_device *hogdev);
+struct hog_device *hog_device_find(GSList *list, const char *path);
diff --git a/profiles/input/hog_manager.c b/profiles/input/hog_manager.c
index 9c23980..c83c345 100644
--- a/profiles/input/hog_manager.c
+++ b/profiles/input/hog_manager.c
@@ -39,6 +39,7 @@
#include "hog_device.h"
static gboolean suspend_supported = FALSE;
+static GSList *devices = NULL;
static void suspend_callback(void)
{
@@ -53,19 +54,36 @@ static void resume_callback(void)
static int hog_device_probe(struct btd_device *device, GSList *uuids)
{
const char *path = device_get_path(device);
+ struct hog_device *hogdev;
+ int err;
DBG("path %s", path);
- return hog_device_register(device, path);
+ hogdev = hog_device_find(devices, path);
+ if (hogdev)
+ return -EALREADY;
+
+ hogdev = hog_device_register(device, path, &err);
+ if (hogdev == NULL)
+ return err;
+
+ devices = g_slist_append(devices, hogdev);
+
+ return 0;
}
static void hog_device_remove(struct btd_device *device)
{
const gchar *path = device_get_path(device);
+ struct hog_device *hogdev;
DBG("path %s", path);
- hog_device_unregister(path);
+ hogdev = hog_device_find(devices, path);
+ if (hogdev) {
+ devices = g_slist_remove(devices, hogdev);
+ hog_device_unregister(hogdev);
+ }
}
static struct btd_device_driver hog_driver = {
--
1.7.12
^ permalink raw reply related
* [PATCH BlueZ v1 4/6] hog: Create a FIFO for dummy suspend
From: Claudio Takahasi @ 2012-08-29 20:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1346273590-16693-1-git-send-email-claudio.takahasi@openbossa.org>
This patch creates a FIFO on "/tmp/hogsuspend" to allow the users to
test the HoG suspend(HID Control Point) when the dummy back-end is
enabled.
---
profiles/input/suspend-dummy.c | 102 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 101 insertions(+), 1 deletion(-)
diff --git a/profiles/input/suspend-dummy.c b/profiles/input/suspend-dummy.c
index 282d3fb..f2941fe 100644
--- a/profiles/input/suspend-dummy.c
+++ b/profiles/input/suspend-dummy.c
@@ -26,21 +26,121 @@
#include <config.h>
#endif
+#include <errno.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "log.h"
#include "suspend.h"
+#define HOG_SUSPEND_FIFO "/tmp/hogsuspend"
+
static suspend_event suspend_cb = NULL;
static resume_event resume_cb = NULL;
+static GIOChannel *fifoio = NULL;
+
+static int fifo_open(void);
+
+static gboolean read_fifo(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+ gchar buffer[12];
+ gsize offset, left, bread;
+ GIOStatus iostatus;
+
+ if (cond & (G_IO_ERR | G_IO_HUP))
+ goto failed;
+
+ offset = 0;
+ left = sizeof(buffer) - 1;
+ memset(buffer, 0, sizeof(buffer));
+
+ do {
+ iostatus = g_io_channel_read_chars(io, &buffer[offset], left,
+ &bread, NULL);
+
+ offset += bread;
+ left -= bread;
+ if (left == 0)
+ break;
+ } while (iostatus == G_IO_STATUS_NORMAL);
+
+ if (g_ascii_strncasecmp("suspend", buffer, 7) == 0)
+ suspend_cb();
+ else if (g_ascii_strncasecmp("resume", buffer, 6) == 0)
+ resume_cb();
+
+ return TRUE;
+
+failed:
+ /*
+ * Both ends needs to be open simultaneously before proceeding any input
+ * or output operation. When the remote closes the channel, hup signal is
+ * received on this end.
+ */
+
+ g_io_channel_unref(fifoio);
+ fifoio = NULL;
+
+ fifo_open();
+
+ return FALSE;
+}
+
+static int fifo_open(void)
+{
+ GIOCondition condition = G_IO_IN | G_IO_ERR | G_IO_HUP;
+ int fd;
+
+ fd = open(HOG_SUSPEND_FIFO, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ int err = -errno;
+ error("Can't open FIFO (%s): %s(%d)", HOG_SUSPEND_FIFO,
+ strerror(-err), -err);
+ return err;
+ }
+
+ fifoio = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(fifoio, TRUE);
+
+ g_io_add_watch(fifoio, condition, read_fifo, NULL);
+
+ return 0;
+}
int suspend_init(suspend_event suspend, resume_event resume)
{
+ int ret;
+
suspend_cb = suspend;
resume_cb = resume;
- return 0;
+ if (mkfifo(HOG_SUSPEND_FIFO, S_IRWXU) < 0) {
+ int err = -errno;
+ error("Can't create FIFO (%s) : %s(%d)", HOG_SUSPEND_FIFO,
+ strerror(-err), -err);
+ return err;
+ }
+
+ ret = fifo_open();
+ if (ret < 0)
+ remove(HOG_SUSPEND_FIFO);
+
+ return ret;
}
void suspend_exit(void)
{
+ if (fifoio) {
+ g_io_channel_shutdown(fifoio, FALSE, NULL);
+ g_io_channel_unref(fifoio);
+ }
+
+ remove(HOG_SUSPEND_FIFO);
}
--
1.7.12
^ 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