* [PATCH BlueZ 6/6 v2] tools: Emit Seeked signal if Position changes
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
MPRIS spec says PropertiesChanged is not emitted for Position, which is
probably to make clear that progress is done using the rate, so instead
Seeked should be emitted.
---
tools/mpris-player.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 5903ca1..95ef8ab 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -1650,6 +1650,8 @@ static void player_property_changed(GDBusProxy *proxy, const char *name,
{
struct player *player;
const char *property;
+ uint32_t position;
+ uint64_t value;
player = find_player(proxy);
if (player == NULL)
@@ -1662,6 +1664,18 @@ static void player_property_changed(GDBusProxy *proxy, const char *name,
g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
MPRIS_PLAYER_INTERFACE,
property);
+
+ if (strcasecmp(name, "Position") != 0)
+ return;
+
+ dbus_message_iter_get_basic(iter, &position);
+
+ value = position * 1000;
+
+ g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE, "Seeked",
+ DBUS_TYPE_INT64, &value,
+ DBUS_TYPE_INVALID);
}
static void transport_property_changed(GDBusProxy *proxy, const char *name,
--
1.8.1
^ permalink raw reply related
* [PATCH BlueZ 5/6 v2] tools: Add volume support for mpris-player
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This uses MediaTransport1 to track the Volume changes.
---
tools/mpris-player.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 178 insertions(+), 9 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index c8377ec..5903ca1 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -43,6 +43,7 @@
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
@@ -55,6 +56,7 @@ static DBusConnection *sys = NULL;
static DBusConnection *session = NULL;
static GDBusClient *client = NULL;
static GSList *players = NULL;
+static GSList *transports = NULL;
struct player {
char *name;
@@ -62,6 +64,7 @@ struct player {
DBusConnection *conn;
GDBusProxy *proxy;
GDBusProxy *device;
+ GDBusProxy *transport;
};
typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
@@ -793,6 +796,9 @@ static void player_free(void *data)
g_dbus_proxy_unref(player->device);
g_dbus_proxy_unref(player->proxy);
+ if (player->transport)
+ g_dbus_proxy_unref(player->transport);
+
g_free(player->name);
g_free(player->bus_name);
g_free(player);
@@ -1277,6 +1283,30 @@ static gboolean get_enable(const GDBusPropertyTable *property,
}
+static gboolean get_volume(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ double value = 0.0;
+ uint16_t volume;
+ DBusMessageIter var;
+
+ if (player->transport == NULL)
+ goto done;
+
+ if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
+ goto done;
+
+ dbus_message_iter_get_basic(&var, &volume);
+
+ value = (double) volume / 127;
+
+done:
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+ return TRUE;
+}
+
static const GDBusMethodTable player_methods[] = {
{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1301,7 +1331,7 @@ static const GDBusPropertyTable player_properties[] = {
{ "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
{ "Position", "x", get_position, NULL, position_exists },
{ "Metadata", "a{sv}", get_track, NULL, track_exists },
- { "Volume", "d", get_double, NULL, NULL },
+ { "Volume", "d", get_volume, NULL, NULL },
{ "CanGoNext", "b", get_enable, NULL, NULL },
{ "CanGoPrevious", "b", get_enable, NULL, NULL },
{ "CanPlay", "b", get_enable, NULL, NULL },
@@ -1355,12 +1385,33 @@ static char *mpris_busname(char *name)
g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
}
+static GDBusProxy *find_transport_by_path(const char *path)
+{
+ GSList *l;
+
+ for (l = transports; l; l = l->next) {
+ GDBusProxy *transport = l->data;
+ DBusMessageIter iter;
+ const char *value;
+
+ if (!g_dbus_proxy_get_property(transport, "Device", &iter))
+ continue;
+
+ dbus_message_iter_get_basic(&iter, &value);
+
+ if (strcmp(path, value) == 0)
+ return transport;
+ }
+
+ return NULL;
+}
+
static void register_player(GDBusProxy *proxy)
{
struct player *player;
DBusMessageIter iter;
const char *path, *name;
- GDBusProxy *device;
+ GDBusProxy *device, *transport;
if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
return;
@@ -1416,6 +1467,10 @@ static void register_player(GDBusProxy *proxy)
goto fail;
}
+ transport = find_transport_by_path(path);
+ if (transport)
+ player->transport = g_dbus_proxy_ref(transport);
+
return;
fail:
@@ -1423,6 +1478,47 @@ fail:
player_free(player);
}
+static struct player *find_player_by_device(const char *device)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+ const char *path = g_dbus_proxy_get_path(player->device);
+
+ if (g_strcmp0(device, path) == 0)
+ return player;
+ }
+
+ return NULL;
+}
+
+static void register_transport(GDBusProxy *proxy)
+{
+ struct player *player;
+ DBusMessageIter iter;
+ const char *path;
+
+ if (g_slist_find(transports, proxy) != NULL)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ transports = g_slist_append(transports, proxy);
+
+ player = find_player_by_device(path);
+ if (player == NULL || player->transport != NULL)
+ return;
+
+ player->transport = g_dbus_proxy_ref(proxy);
+}
+
static void proxy_added(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -1441,6 +1537,10 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
printf("Bluetooth Player %s found\n",
g_dbus_proxy_get_path(proxy));
register_player(proxy);
+ } else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
+ printf("Bluetooth Transport %s found\n",
+ g_dbus_proxy_get_path(proxy));
+ register_transport(proxy);
}
}
@@ -1466,6 +1566,37 @@ static struct player *find_player(GDBusProxy *proxy)
return NULL;
}
+static struct player *find_player_by_transport(GDBusProxy *proxy)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (player->transport == proxy)
+ return player;
+ }
+
+ return NULL;
+}
+
+static void unregister_transport(GDBusProxy *proxy)
+{
+ struct player *player;
+
+ if (g_slist_find(transports, proxy) == NULL)
+ return;
+
+ transports = g_slist_remove(transports, proxy);
+
+ player = find_player_by_transport(proxy);
+ if (player == NULL)
+ return;
+
+ g_dbus_proxy_unref(player->transport);
+ player->transport = NULL;
+}
+
static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -1491,6 +1622,10 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
printf("Bluetooth Player %s removed\n",
g_dbus_proxy_get_path(proxy));
unregister_player(player);
+ } else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
+ printf("Bluetooth Transport %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_transport(proxy);
}
}
@@ -1510,16 +1645,11 @@ static const char *property_to_mpris(const char *property)
return NULL;
}
-static void property_changed(GDBusProxy *proxy, const char *name,
+static void player_property_changed(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
struct player *player;
- const char *interface, *property;
-
- interface = g_dbus_proxy_get_interface(proxy);
-
- if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) != 0)
- return;
+ const char *property;
player = find_player(proxy);
if (player == NULL)
@@ -1534,6 +1664,45 @@ static void property_changed(GDBusProxy *proxy, const char *name,
property);
}
+static void transport_property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct player *player;
+ DBusMessageIter var;
+ const char *path;
+
+ if (strcasecmp(name, "Volume") != 0)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &var))
+ return;
+
+ dbus_message_iter_get_basic(&var, &path);
+
+ player = find_player_by_device(path);
+ if (player == NULL)
+ return;
+
+ g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ name);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
+ return player_property_changed(proxy, name, iter, user_data);
+
+ if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
+ return transport_property_changed(proxy, name, iter,
+ user_data);
+}
+
int main(int argc, char *argv[])
{
guint owner_watch, properties_watch;
--
1.8.1
^ permalink raw reply related
* [PATCH BlueZ 4/6 v2] tools: Make mpris-player to export org.mpris.MediaPlayer2
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for org.mpris.MediaPlayer2 interface whic is also
mandatory accourding to MPRIS spec.
---
tools/mpris-player.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 320309e..c8377ec 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -44,6 +44,7 @@
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
+#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
@@ -1275,6 +1276,7 @@ static gboolean get_enable(const GDBusPropertyTable *property,
return TRUE;
}
+
static const GDBusMethodTable player_methods[] = {
{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1309,6 +1311,39 @@ static const GDBusPropertyTable player_properties[] = {
{ }
};
+static gboolean get_disable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ dbus_bool_t value = FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static gboolean get_name(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &player->name);
+
+ return TRUE;
+}
+
+static const GDBusMethodTable mpris_methods[] = {
+ { }
+};
+
+static const GDBusPropertyTable mpris_properties[] = {
+ { "CanQuit", "b", get_disable, NULL, NULL },
+ { "Fullscreen", "b", get_disable, NULL, NULL },
+ { "CanSetFullscreen", "b", get_disable, NULL, NULL },
+ { "CanRaise", "b", get_disable, NULL, NULL },
+ { "HasTrackList", "b", get_disable, NULL, NULL },
+ { "Identity", "s", get_name, NULL, NULL },
+ { }
+};
#define a_z "abcdefghijklmnopqrstuvwxyz"
#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -1360,6 +1395,17 @@ static void register_player(GDBusProxy *proxy)
}
if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_INTERFACE,
+ mpris_methods,
+ NULL,
+ mpris_properties,
+ player, NULL)) {
+ fprintf(stderr, "Could not register interface %s",
+ MPRIS_INTERFACE);
+ goto fail;
+ }
+
+ if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
MPRIS_PLAYER_INTERFACE,
player_methods,
player_signals,
--
1.8.1
^ permalink raw reply related
* [PATCH BlueZ 3/6 v2] tools: Convert player's properties changed signals to MPRIS
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thsi convert properties changed signals from org.bluez.MediaPlayer1 to
org.mpris.MediaPlayer2.Player interface.
---
tools/mpris-player.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 7183bf6..320309e 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -1448,6 +1448,46 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
}
}
+static const char *property_to_mpris(const char *property)
+{
+ if (strcasecmp(property, "Repeat") == 0)
+ return "LoopStatus";
+ else if (strcasecmp(property, "Shuffle") == 0)
+ return "Shuffle";
+ else if (strcasecmp(property, "Status") == 0)
+ return "PlaybackStatus";
+ else if (strcasecmp(property, "Position") == 0)
+ return "Position";
+ else if (strcasecmp(property, "Track") == 0)
+ return "Metadata";
+
+ return NULL;
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct player *player;
+ const char *interface, *property;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) != 0)
+ return;
+
+ player = find_player(proxy);
+ if (player == NULL)
+ return;
+
+ property = property_to_mpris(name);
+ if (property == NULL)
+ return;
+
+ g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ property);
+}
+
int main(int argc, char *argv[])
{
guint owner_watch, properties_watch;
@@ -1503,7 +1543,7 @@ int main(int argc, char *argv[])
g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
- NULL, NULL);
+ property_changed, NULL);
g_main_loop_run(main_loop);
--
1.8.1
^ permalink raw reply related
* [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This add write support for Shuffle and LoopStatus properties of
org.mpris.MediaPlayer2.Player interface.
---
tools/mpris-player.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 2 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index d58e53f..7183bf6 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -992,6 +992,58 @@ static gboolean get_repeat(const GDBusPropertyTable *property,
return TRUE;
}
+static const char *loopstatus_to_repeat(const char *value)
+{
+ if (strcasecmp(value, "None") == 0)
+ return "off";
+ else if (strcasecmp(value, "Track") == 0)
+ return "singletrack";
+ else if (strcasecmp(value, "Playlist") == 0)
+ return "alltracks";
+
+ return NULL;
+}
+
+static void property_result(const DBusError *err, void *user_data)
+{
+ GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
+
+ if (!dbus_error_is_set(err))
+ return g_dbus_pending_property_success(id);
+
+ g_dbus_pending_property_error(id, err->name, err->message);
+}
+
+static void set_repeat(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct player *player = data;
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ value = loopstatus_to_repeat(value);
+ if (value == NULL) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
+ DBUS_TYPE_STRING, value,
+ property_result, GUINT_TO_POINTER(id),
+ NULL);
+}
+
static gboolean get_double(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1030,6 +1082,30 @@ static gboolean get_shuffle(const GDBusPropertyTable *property,
return TRUE;
}
+static void set_shuffle(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct player *player = data;
+ dbus_bool_t shuffle;
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &shuffle);
+ value = shuffle ? "alltracks" : "off";
+
+ g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
+ DBUS_TYPE_STRING, value,
+ property_result, GUINT_TO_POINTER(id),
+ NULL);
+}
+
static gboolean position_exists(const GDBusPropertyTable *property, void *data)
{
DBusMessageIter iter;
@@ -1216,11 +1292,11 @@ static const GDBusSignalTable player_signals[] = {
static const GDBusPropertyTable player_properties[] = {
{ "PlaybackStatus", "s", get_status, NULL, status_exists },
- { "LoopStatus", "s", get_repeat, NULL, repeat_exists },
+ { "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
{ "Rate", "d", get_double, NULL, NULL },
{ "MinimumRate", "d", get_double, NULL, NULL },
{ "MaximumRate", "d", get_double, NULL, NULL },
- { "Shuffle", "b", get_shuffle, NULL, shuffle_exists },
+ { "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
{ "Position", "x", get_position, NULL, position_exists },
{ "Metadata", "a{sv}", get_track, NULL, track_exists },
{ "Volume", "d", get_double, NULL, NULL },
--
1.8.1
^ permalink raw reply related
* [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface
From: Luiz Augusto von Dentz @ 2013-01-24 9:57 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Players found are exported in private connections using
org.mpris.MediaPlayer2.<device name> on the session bus.
---
v2: Fix generating invalid player bus name if device name contains invalid
chars.
tools/mpris-player.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 623 insertions(+), 21 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 246791a..d58e53f 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -32,6 +32,7 @@
#include <signal.h>
#include <getopt.h>
#include <string.h>
+#include <inttypes.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -41,13 +42,29 @@
#define BLUEZ_PATH "/org/bluez"
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
+#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
+#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
static GMainLoop *main_loop;
static GDBusProxy *adapter = NULL;
static DBusConnection *sys = NULL;
static DBusConnection *session = NULL;
+static GDBusClient *client = NULL;
+static GSList *players = NULL;
+
+struct player {
+ char *name;
+ char *bus_name;
+ DBusConnection *conn;
+ GDBusProxy *proxy;
+ GDBusProxy *device;
+};
+
+typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata);
static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
void *val);
@@ -190,7 +207,8 @@ static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
return 0;
}
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
+static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
+ parse_metadata_func func)
{
DBusMessageIter dict;
int ctype;
@@ -216,7 +234,7 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
- if (parse_metadata_entry(&entry, key, metadata) < 0)
+ if (func(&entry, key, metadata) < 0)
return -EINVAL;
dbus_message_iter_next(&dict);
@@ -225,7 +243,8 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
return 0;
}
-static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
+static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
+ parse_metadata_func func)
{
DBusMessageIter value, metadata;
@@ -237,7 +256,7 @@ static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
- parse_metadata(dict, &metadata);
+ parse_metadata(dict, &metadata, func);
dbus_message_iter_close_container(&value, &metadata);
dbus_message_iter_close_container(iter, &value);
@@ -260,7 +279,7 @@ static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
if (strcasecmp(key, "Metadata") == 0)
- append_metadata(&entry, val);
+ append_metadata(&entry, val, parse_metadata_entry);
else
append_variant(&entry, type, val);
@@ -509,21 +528,29 @@ done:
static void remove_player(DBusConnection *conn, const char *sender)
{
DBusMessage *msg;
- char *path;
+ char *path, *owner;
if (!adapter)
return;
+ path = sender2path(sender);
+ dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+ if (owner == NULL) {
+ g_free(path);
+ return;
+ }
+
msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
g_dbus_proxy_get_path(adapter),
BLUEZ_MEDIA_INTERFACE,
"UnregisterPlayer");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
+ g_free(path);
return;
}
- path = sender2path(sender);
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
@@ -540,10 +567,16 @@ static gboolean properties_changed(DBusConnection *conn,
{
DBusMessageIter iter;
const char *iface;
- char *path;
+ char *path, *owner;
dbus_message_iter_init(msg, &iter);
+ path = sender2path(dbus_message_get_sender(msg));
+ dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+ if (owner == NULL)
+ goto done;
+
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -553,14 +586,28 @@ static gboolean properties_changed(DBusConnection *conn,
dbus_message_iter_next(&iter);
- path = sender2path(dbus_message_get_sender(msg));
parse_properties(conn, path, &iter, NULL);
+done:
g_free(path);
return TRUE;
}
+static struct player *find_player_by_bus_name(const char *name)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (strcmp(player->bus_name, name) == 0)
+ return player;
+ }
+
+ return NULL;
+}
+
static gboolean name_owner_changed(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -581,7 +628,7 @@ static gboolean name_owner_changed(DBusConnection *conn,
if (*new == '\0') {
printf("player %s at %s disappear\n", name, old);
remove_player(conn, old);
- } else {
+ } else if (find_player_by_bus_name(name) == NULL) {
printf("player %s at %s found\n", name, new);
add_player(conn, name, new);
}
@@ -733,23 +780,570 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
printf("org.bluez disappeared\n");
}
-static void proxy_added(GDBusProxy *proxy, void *user_data)
+static void player_free(void *data)
{
- const char *interface;
+ struct player *player = data;
+
+ if (player->conn) {
+ dbus_connection_close(player->conn);
+ dbus_connection_unref(player->conn);
+ }
+
+ g_dbus_proxy_unref(player->device);
+ g_dbus_proxy_unref(player->proxy);
+
+ g_free(player->name);
+ g_free(player->bus_name);
+ g_free(player);
+}
+
+struct pending_call {
+ struct player *player;
+ DBusMessage *msg;
+};
+
+static void pending_call_free(void *data)
+{
+ struct pending_call *p = data;
+
+ if (p->msg)
+ dbus_message_unref(p->msg);
+
+ g_free(p);
+}
+
+static void player_reply(DBusMessage *message, void *user_data)
+{
+ struct pending_call *p = user_data;
+ struct player *player = p->player;
+ DBusMessage *msg = p->msg;
+ DBusMessage *reply;
+ DBusError err;
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ fprintf(stderr, "error: %s", err.name);
+ reply = g_dbus_create_error(msg, err.name, err.message);
+ dbus_error_free(&err);
+ } else
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+ g_dbus_send_message(player->conn, reply);
+}
+
+static void player_control(struct player *player, DBusMessage *msg,
+ const char *name)
+{
+ struct pending_call *p;
+
+ p = g_new0(struct pending_call, 1);
+ p->player = player;
+ p->msg = dbus_message_ref(msg);
+
+ g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
+ p, pending_call_free);
+}
+
+static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ if (strcasecmp(status, "Playing") == 0)
+ player_control(player, msg, "Pause");
+ else
+ player_control(player, msg, "Play");
+
+ return NULL;
+}
+
+static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Play");
+
+ return NULL;
+}
+
+static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Pause");
+
+ return NULL;
+}
+
+static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Stop");
+
+ return NULL;
+}
+
+static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Next");
+
+ return NULL;
+}
+
+static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Previous");
+
+ return NULL;
+}
+
+static gboolean status_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Status", &iter);
+}
+
+static const char *status_to_playback(const char *status)
+{
+ if (strcasecmp(status, "playing") == 0)
+ return "Playing";
+ else if (strcasecmp(status, "paused") == 0)
+ return "Paused";
+ else
+ return "Stopped";
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ status = status_to_playback(status);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+ return TRUE;
+}
+
+static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
+}
+
+static const char *repeat_to_loopstatus(const char *value)
+{
+ if (strcasecmp(value, "off") == 0)
+ return "None";
+ else if (strcasecmp(value, "singletrack") == 0)
+ return "Track";
+ else if (strcasecmp(value, "alltracks") == 0)
+ return "Playlist";
+
+ return NULL;
+}
+
+static gboolean get_repeat(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ status = repeat_to_loopstatus(status);
+ if (status == NULL)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+ return TRUE;
+}
+
+static gboolean get_double(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ double value = 1.0;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+ return TRUE;
+}
+
+static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
+}
+
+static gboolean get_shuffle(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *string;
+ dbus_bool_t shuffle;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &string);
+
+ shuffle = strcmp(string, "off") != 0;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
+
+ return TRUE;
+}
+
+static gboolean position_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
+}
- if (adapter != NULL)
+static gboolean get_position(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter var;
+ uint32_t position;
+ int64_t value;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&var, &position);
+
+ value = position * 1000;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
+
+ return TRUE;
+}
+
+static gboolean track_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
+}
+
+static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
+
+ return TRUE;
+}
+
+static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ char **value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ value = dbus_malloc0(sizeof(char *));
+
+ dbus_message_iter_get_basic(iter, &(value[0]));
+
+ dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
+
+ dbus_free(value);
+
+ return TRUE;
+}
+
+static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ uint32_t duration;
+ int64_t value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &duration);
+
+ value = duration * 1000;
+
+ dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
+
+ return TRUE;
+}
+
+static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ uint32_t value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
+
+ return TRUE;
+}
+
+static int parse_track_entry(DBusMessageIter *entry, const char *key,
+ DBusMessageIter *metadata)
+{
+ DBusMessageIter var;
+
+ printf("metadata %s found\n", key);
+
+ if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(entry, &var);
+
+ if (strcasecmp(key, "Title") == 0) {
+ if (!parse_string_metadata(&var, "xesam:title", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Artist") == 0) {
+ if (!parse_array_metadata(&var, "xesam:artist", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Album") == 0) {
+ if (!parse_string_metadata(&var, "xesam:album", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Genre") == 0) {
+ if (!parse_array_metadata(&var, "xesam:genre", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Duration") == 0) {
+ if (!parse_int64_metadata(&var, "mpris:length", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "TrackNumber") == 0) {
+ if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static gboolean get_track(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter var, metadata;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
+ return FALSE;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+ parse_metadata(&var, &metadata, parse_track_entry);
+
+ dbus_message_iter_close_container(iter, &metadata);
+
+ return TRUE;
+}
+
+static gboolean get_enable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ dbus_bool_t value = TRUE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static const GDBusMethodTable player_methods[] = {
+ { GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
+ { GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
+ { GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
+ { GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
+ { GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
+ { GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
+ { }
+};
+
+static const GDBusSignalTable player_signals[] = {
+ { GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
+ { }
+};
+
+static const GDBusPropertyTable player_properties[] = {
+ { "PlaybackStatus", "s", get_status, NULL, status_exists },
+ { "LoopStatus", "s", get_repeat, NULL, repeat_exists },
+ { "Rate", "d", get_double, NULL, NULL },
+ { "MinimumRate", "d", get_double, NULL, NULL },
+ { "MaximumRate", "d", get_double, NULL, NULL },
+ { "Shuffle", "b", get_shuffle, NULL, shuffle_exists },
+ { "Position", "x", get_position, NULL, position_exists },
+ { "Metadata", "a{sv}", get_track, NULL, track_exists },
+ { "Volume", "d", get_double, NULL, NULL },
+ { "CanGoNext", "b", get_enable, NULL, NULL },
+ { "CanGoPrevious", "b", get_enable, NULL, NULL },
+ { "CanPlay", "b", get_enable, NULL, NULL },
+ { "CanPause", "b", get_enable, NULL, NULL },
+ { "CanSeek", "b", get_enable, NULL, NULL },
+ { "CanControl", "b", get_enable, NULL, NULL },
+ { }
+};
+
+
+#define a_z "abcdefghijklmnopqrstuvwxyz"
+#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define _0_9 "_0123456789"
+
+static char *mpris_busname(char *name)
+{
+ return g_strconcat(MPRIS_BUS_NAME,
+ g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
+}
+
+static void register_player(GDBusProxy *proxy)
+{
+ struct player *player;
+ DBusMessageIter iter;
+ const char *path, *name;
+ GDBusProxy *device;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
+ if (device == NULL)
+ return;
+
+ if (!g_dbus_proxy_get_property(device, "Name", &iter))
return;
+ dbus_message_iter_get_basic(&iter, &name);
+
+ player = g_new0(struct player, 1);
+ player->name = g_strdup(name);
+ player->bus_name = mpris_busname(player->name);
+ player->proxy = g_dbus_proxy_ref(proxy);
+ player->device = device;
+
+ players = g_slist_prepend(players, player);
+
+ printf("Player %s created\n", player->bus_name);
+
+ player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
+ NULL);
+ if (!session) {
+ fprintf(stderr, "Could not register bus name %s",
+ player->bus_name);
+ goto fail;
+ }
+
+ if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ player_methods,
+ player_signals,
+ player_properties,
+ player, player_free)) {
+ fprintf(stderr, "Could not register interface %s",
+ MPRIS_PLAYER_INTERFACE);
+ goto fail;
+ }
+
+ return;
+
+fail:
+ players = g_slist_remove(players, player);
+ player_free(player);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
interface = g_dbus_proxy_get_interface(proxy);
if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
+ if (adapter != NULL)
+ return;
+
printf("Bluetooth Adapter %s found\n",
g_dbus_proxy_get_path(proxy));
adapter = proxy;
list_names(session);
+ } else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
+ printf("Bluetooth Player %s found\n",
+ g_dbus_proxy_get_path(proxy));
+ register_player(proxy);
}
}
+static void unregister_player(struct player *player)
+{
+ players = g_slist_remove(players, player);
+
+ g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE);
+}
+
+static struct player *find_player(GDBusProxy *proxy)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (player->proxy == proxy)
+ return player;
+ }
+
+ return NULL;
+}
+
static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -759,19 +1353,27 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
interface = g_dbus_proxy_get_interface(proxy);
- if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE))
- return;
+ if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
+ if (adapter != proxy)
+ return;
+ printf("Bluetooth Adapter %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ adapter = NULL;
+ } else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
+ struct player *player;
- if (adapter != proxy)
- return;
+ player = find_player(proxy);
+ if (player == NULL)
+ return;
- printf("Bluetooth Adapter %s removed\n", g_dbus_proxy_get_path(proxy));
- adapter = NULL;
+ printf("Bluetooth Player %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_player(player);
+ }
}
int main(int argc, char *argv[])
{
- GDBusClient *client;
guint owner_watch, properties_watch;
struct sigaction sa;
int opt;
@@ -825,7 +1427,7 @@ int main(int argc, char *argv[])
g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
- NULL, NULL);
+ NULL, NULL);
g_main_loop_run(main_loop);
--
1.8.1
^ permalink raw reply related
* [RFC PATCH v0 6/6] Bluetooth: Add support for UUID-128 bit parsing for EIR
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>
This patch add the support for UUID-128 bit parsing for the EIR.
Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
net/bluetooth/mgmt.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e1fbf95..52cce2f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -586,6 +586,52 @@ static u16 update_eir_uuid32_list(u8 *list32, u8 *uuid, bool updated_16, bool up
return eir_len;
}
+static u16 update_eir_uuid128_list(u8 *list128, u8 *uuid, bool updated_16, bool updated_32, u16 eir_len, bool *truncated)
+{
+ int i;
+ u128 *uuid128_list = (u128 *) list128;
+ u128 u;
+
+ memset(u.data, 0, sizeof(u128));
+
+ /* Stop if not enough space to put next UUID128 */
+ if (eir_len + 2 + sizeof(u128) > HCI_MAX_EIR_LENGTH) {
+ *truncated = true;
+ return 1;
+ }
+
+ i = 0;
+
+ /* Comparing uuid128_list[i] with 0*/
+ while (memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+ if (!memcmp(uuid128_list[i].data, uuid, sizeof(u128)))
+ break;
+
+ ++i;
+ }
+
+ if (!memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+
+ /* if any other uuid types has been already added into the
+ * corresponding list, then consider it's header length(2 bytes)
+ * in eir_len calculation.
+ */
+ if (!memcmp(uuid128_list[0].data, u.data, sizeof(u128))) {
+ if (updated_16)
+ eir_len += 2;
+
+ if (updated_32)
+ eir_len += 2;
+
+ }
+
+ memcpy(uuid128_list[i].data, uuid, sizeof(u128));
+ eir_len += sizeof(u128);
+ }
+
+ return eir_len;
+}
+
static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
{
int i;
@@ -666,10 +712,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u16 eir_len = 0;
u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
+ u128 uuid128_list[HCI_MAX_EIR_LENGTH / sizeof(u128)];
struct bt_uuid *uuid;
size_t name_len;
- bool truncated_16 = false, truncated_32 = false;
+ bool truncated_16 = false, truncated_32 = false, truncated_128 = false;
bool updated_128 = false;
+ u128 u;
name_len = strlen(hdev->dev_name);
@@ -714,6 +762,8 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
memset(uuid16_list, 0, sizeof(uuid16_list));
memset(uuid32_list, 0, sizeof(uuid32_list));
+ memset(uuid128_list, 0, sizeof(uuid128_list));
+ memset(u.data, 0, sizeof(u128));
list_for_each_entry(uuid, &hdev->uuids, list) {
u16 uuid_type;
@@ -746,6 +796,23 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
break;
eir_len = ret;
+ } else {
+ ret = update_eir_uuid128_list((u8 *) uuid128_list,
+ uuid->uuid,
+ uuid16_list[0] ? 1 : 0,
+ uuid32_list[0] ? 1 : 0,
+ eir_len,
+ &truncated_128);
+ /* Truncated */
+ if (ret == 1)
+ break;
+
+ /* In other cases we will directly check uuid*_list[0].
+ * Here we use a flag updated_128 to avoid memcmp().
+ */
+ updated_128 = true;
+
+ eir_len = ret;
}
} /* list_for_each_entry end */
@@ -760,6 +827,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
EIR_TYPE_UUID32, truncated_32);
eir_len += 2;
}
+
+ if (memcmp(uuid128_list[0].data, u.data, sizeof(u128)) != 0) {
+ ptr = prepare_eir_from_list((u8 *) uuid128_list, ptr,
+ EIR_TYPE_UUID128, truncated_128);
+ eir_len += 2;
+ }
}
static int update_eir(struct hci_dev *hdev)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v0 5/6] Bluetooth: Add support for UUID-32 bit parsing for EIR
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>
This patch add the support for UUID 32-bit parsing for EIR.
Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
net/bluetooth/mgmt.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 446e4d3..e1fbf95 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -483,6 +483,18 @@ static u16 get_uuid16(u8 *uuid128)
return (u16) val;
}
+static u32 get_uuid32(u8 *uuid128)
+{
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (bluetooth_base_uuid[i] != uuid128[i])
+ return 0;
+ }
+
+ return get_unaligned_le32(&uuid128[12]);
+}
+
static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool updated_128, u16 eir_len, bool *truncated)
{
int i;
@@ -533,6 +545,47 @@ static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool up
return eir_len;
}
+static u16 update_eir_uuid32_list(u8 *list32, u8 *uuid, bool updated_16, bool updated_128, u16 eir_len, bool *truncated)
+{
+ int i;
+ u32 uuid32;
+ u32 *uuid32_list = (u32 *) list32;
+
+ /* Group all UUID32 types */
+ uuid32 = get_uuid32(uuid);
+
+ /* Stop if not enough space to put next UUID32 */
+ if (eir_len + 2 + sizeof(u32) > HCI_MAX_EIR_LENGTH) {
+ *truncated = true;
+ return 1;
+ }
+
+ /* Check for duplicates */
+ for (i = 0; uuid32_list[i] != 0; i++)
+ if (uuid32_list[i] == uuid32)
+ break;
+
+ if (uuid32_list[i] == 0) {
+
+ /* if any other uuid types has been already added into the
+ * corresponding list, then consider it's header length(2 bytes)
+ * in eir_len calculation.
+ */
+ if (uuid32_list[0] == 0) {
+ if (updated_16)
+ eir_len += 2;
+
+ if (updated_128 == true)
+ eir_len += 2;
+ }
+
+ uuid32_list[i] = uuid32;
+ eir_len += sizeof(u32);
+ }
+
+ return eir_len;
+}
+
static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
{
int i;
@@ -615,7 +668,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
struct bt_uuid *uuid;
size_t name_len;
- bool truncated_16 = false;
+ bool truncated_16 = false, truncated_32 = false;
bool updated_128 = false;
name_len = strlen(hdev->dev_name);
@@ -682,6 +735,17 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
break;
eir_len = ret;
+ } else if (uuid_type == EIR_TYPE_UUID32) {
+ ret = update_eir_uuid32_list((u8 *) uuid32_list,
+ uuid->uuid,
+ uuid16_list[0] ? 1 : 0,
+ updated_128, eir_len,
+ &truncated_32);
+ /* Truncated */
+ if (ret == 1)
+ break;
+
+ eir_len = ret;
}
} /* list_for_each_entry end */
@@ -690,6 +754,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
EIR_TYPE_UUID16, truncated_16);
eir_len += 2;
}
+
+ if (uuid32_list[0]) {
+ ptr = prepare_eir_from_list((u8 *) uuid32_list, ptr,
+ EIR_TYPE_UUID32, truncated_32);
+ eir_len += 2;
+ }
}
static int update_eir(struct hci_dev *hdev)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v0 4/6] Bluetooth: Add EIR UUID-16 bit parsing for EIR
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>
Here we are enhancing the existing code to support 16bit UUID's along
with other types. Also it fixes one issue related to EIR 16 bit UUID
updation. Earlier UUID 16bit updation fails further when any other
non 16 bit UUID types are trying to get registed.
Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
net/bluetooth/mgmt.c | 117 ++++++++++++++++++++++++++++++++------------------
1 file changed, 75 insertions(+), 42 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d2569f8..446e4d3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -483,6 +483,56 @@ static u16 get_uuid16(u8 *uuid128)
return (u16) val;
}
+static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool updated_128, u16 eir_len, bool *truncated)
+{
+ int i;
+ u16 uuid16;
+ u16 *uuid16_list = (u16 *) list16;
+
+ /* Group all UUID16 types */
+ uuid16 = get_uuid16(uuid);
+ if (uuid16 == 0)
+ return 0;
+
+ if (uuid16 < 0x1100)
+ return 0;
+
+ if (uuid16 == PNP_INFO_SVCLASS_ID)
+ return 0;
+
+ /* Stop if not enough space to put next UUID16 */
+ if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
+ *truncated = true;
+ return 1;
+ }
+
+ /* Check for duplicates */
+ for (i = 0; uuid16_list[i] != 0; i++)
+ if (uuid16_list[i] == uuid16)
+ return 0;
+
+ if (uuid16_list[i] == 0) {
+
+ /* if any other uuid types has been already added into the
+ * corresponding list, then consider it's header length(2 bytes)
+ * in eir_len calculation.
+ */
+ if (uuid16_list[0] == 0) {
+
+ if (updated_32)
+ eir_len += 2;
+
+ if (updated_128 == true)
+ eir_len += 2;
+ }
+
+ uuid16_list[i] = uuid16;
+ eir_len += sizeof(u16);
+ }
+
+ return eir_len;
+}
+
static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
{
int i;
@@ -562,9 +612,11 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u8 *ptr = data;
u16 eir_len = 0;
u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
- int i, truncated = 0;
+ u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
struct bt_uuid *uuid;
size_t name_len;
+ bool truncated_16 = false;
+ bool updated_128 = false;
name_len = strlen(hdev->dev_name);
@@ -608,54 +660,35 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
}
memset(uuid16_list, 0, sizeof(uuid16_list));
+ memset(uuid32_list, 0, sizeof(uuid32_list));
- /* Group all UUID16 types */
list_for_each_entry(uuid, &hdev->uuids, list) {
- u16 uuid16;
-
- uuid16 = get_uuid16(uuid->uuid);
- if (uuid16 == 0)
- return;
-
- if (uuid16 < 0x1100)
- continue;
-
- if (uuid16 == PNP_INFO_SVCLASS_ID)
- continue;
-
- /* Stop if not enough space to put next UUID */
- if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
- truncated = 1;
- break;
- }
-
- /* Check for duplicates */
- for (i = 0; uuid16_list[i] != 0; i++)
- if (uuid16_list[i] == uuid16)
+ u16 uuid_type;
+ u16 ret;
+
+ uuid_type = get_uuid_type(uuid->uuid);
+
+ if (uuid_type == EIR_TYPE_UUID16) {
+ ret = update_eir_uuid16_list((u8 *) uuid16_list,
+ uuid->uuid,
+ uuid32_list[0] ? 1 : 0,
+ updated_128, eir_len,
+ &truncated_16);
+ if (ret == 0)
+ continue;
+
+ /* Truncated */
+ if (ret == 1)
break;
- if (uuid16_list[i] == 0) {
- uuid16_list[i] = uuid16;
- eir_len += sizeof(u16);
+ eir_len = ret;
}
- }
+ } /* list_for_each_entry end */
- if (uuid16_list[0] != 0) {
- u8 *length = ptr;
-
- /* EIR Data type */
- ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
-
- ptr += 2;
+ if (uuid16_list[0]) {
+ ptr = prepare_eir_from_list((u8 *) uuid16_list, ptr,
+ EIR_TYPE_UUID16, truncated_16);
eir_len += 2;
-
- for (i = 0; uuid16_list[i] != 0; i++) {
- *ptr++ = (uuid16_list[i] & 0x00ff);
- *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
- }
-
- /* EIR Data length */
- *length = (i * sizeof(u16)) + 1;
}
}
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v0 3/6] Bluetooth: Add helper function to prepare the EIR packet from list
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>
This function is used to prepare the final eir data from the
various list. It returns the updated pointer to the buffer.
Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
net/bluetooth/mgmt.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0f32986..d2569f8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -41,6 +41,11 @@ bool enable_hs;
#define EIR_TYPE_UUID32 2
#define EIR_TYPE_UUID128 3
+/* UUID128 type */
+typedef struct {
+ u8 data[16];
+} u128;
+
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
MGMT_OP_READ_INFO,
@@ -478,6 +483,80 @@ static u16 get_uuid16(u8 *uuid128)
return (u16) val;
}
+static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
+{
+ int i;
+ if (type == EIR_TYPE_UUID16) {
+ u8 *length = ptr;
+ u16 *uuid16_list = (u16 *) list;
+
+ /* EIR Data type */
+ ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
+
+ ptr += 2;
+ for (i = 0; uuid16_list[i] != 0; i++) {
+ *ptr++ = (uuid16_list[i] & 0x00ff);
+ *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
+ }
+
+ /* EIR Data length */
+ *length = (i * sizeof(u16)) + 1;
+ return ptr;
+ }
+
+ if (type == EIR_TYPE_UUID32) {
+ u8 *length = ptr;
+ u32 *uuid32_list = (u32 *) list;
+
+ /* EIR Data type */
+ ptr[1] = truncated ? EIR_UUID32_SOME : EIR_UUID32_ALL;
+
+ ptr += 2;
+
+ for (i = 0; uuid32_list[i] != 0; i++) {
+ *ptr++ = (uuid32_list[i] & 0x000000ff);
+ *ptr++ = (uuid32_list[i] & 0x0000ff00) >> 8;
+ *ptr++ = (uuid32_list[i] & 0x00ff0000) >> 16;
+ *ptr++ = (uuid32_list[i] & 0xff000000) >> 24;
+ }
+
+ /* EIR Data length */
+ *length = (i * sizeof(u32)) + 1;
+
+ return ptr;
+ }
+
+ if (type == EIR_TYPE_UUID128) {
+
+ u8 *length = ptr;
+ u128 *uuid128_list = (u128 *) list;
+ u128 u;
+
+ memset(u.data, 0, sizeof(u128));
+ /* EIR Data type */
+ ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
+
+ ptr += 2;
+
+ i = 0;
+ while (memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+
+ memcpy(ptr, uuid128_list[i].data, sizeof(u128));
+
+ ptr += sizeof(u128);
+ i++;
+ }
+
+ /* EIR Data length */
+ *length = (i * sizeof(u128)) + 1;
+
+ return ptr;
+
+ }
+
+ return ptr;
+}
+
static void create_eir(struct hci_dev *hdev, u8 *data)
{
u8 *ptr = data;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v0 2/6] Bluetooth: Add helper function to get the uuid type
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>
This function will return the particular uuid type
Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
net/bluetooth/mgmt.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4fd45a3..0f32986 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -37,6 +37,10 @@ bool enable_hs;
#define MGMT_VERSION 1
#define MGMT_REVISION 2
+#define EIR_TYPE_UUID16 1
+#define EIR_TYPE_UUID32 2
+#define EIR_TYPE_UUID128 3
+
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
MGMT_OP_READ_INFO,
@@ -440,6 +444,23 @@ static u8 bluetooth_base_uuid[] = {
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
+static int get_uuid_type(u8 *uuid128)
+{
+ u32 val;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (bluetooth_base_uuid[i] != uuid128[i])
+ return EIR_TYPE_UUID128;
+ }
+
+ val = get_unaligned_le32(&uuid128[12]);
+ if (val > 0xffff)
+ return EIR_TYPE_UUID32;
+ else
+ return EIR_TYPE_UUID16;
+}
+
static u16 get_uuid16(u8 *uuid128)
{
u32 val;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v0 1/6] Bluetooth: Update the uuid list in reverse order
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>
If we add uuid in the list head, then initially added uuid's might
get lost because of the possibility of Max limit 240 reaches before
reaching the end of the list parsing.
Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e7f944f..4fd45a3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1330,7 +1330,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
memcpy(uuid->uuid, cp->uuid, 16);
uuid->svc_hint = cp->svc_hint;
- list_add(&uuid->list, &hdev->uuids);
+ list_add_tail(&uuid->list, &hdev->uuids);
err = update_class(hdev);
if (err < 0)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH v0 0/6] Addd support for EIR 32 bit and 128 bit UUID's in EIR
From: Syam Sidhardhan @ 2013-01-24 5:57 UTC (permalink / raw)
To: linux-bluetooth
This patch enhances the existing code and add support for the
EIR updation for UUID-32 & UUID-128.
Patch 1: changes the order of the parsing inorder to avoid uuid's getting
overwritten in extreem cases. Since we are reversing the order the
mgmt-tester testcase for "UUID-16 multiple 1" will fail. I'll send the
updated fix for the mgmt-tester with UUID128 testcase.
Since I do not have a setup to test these changes using mgmt-tester,
Chen-yeol Park has help me a lot and tested the changes locally and
it is reported working fine. Thanks Johan for the guidence.
Syam Sidhardhan (6):
Bluetooth: Update the uuid list in reverse order
Bluetooth: Add helper function to get the uuid type
Bluetooth: Add helper function to prepare the EIR packet from list
Bluetooth: Add EIR UUID-16 bit parsing for EIR
Bluetooth: Add support for UUID-32 bit parsing for EIR
Bluetooth: Add support for UUID-128 bit parsing for EIR
net/bluetooth/mgmt.c | 352 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 314 insertions(+), 38 deletions(-)
--
1.7.9.5
^ permalink raw reply
* Patch for AR3011 device
From: Isaac Lindgren @ 2013-01-24 3:56 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: Gustavo Padovan, Johan Hedberg, linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 1563 bytes --]
I was experiencing the problem described on the ath3k Linux wireless page
regarding AR3011 with SFLASH. My device is:
Bus 001 Device 004: ID 04f2:aff1 Chicony Electronics Co., Ltd
To correct this I followed the instructions on the ath3k page and added my
VID/PID to ath3k.c and blacklisted it in btusb.c:
diff -uprN a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
--- a/drivers/bluetooth/ath3k.c 2013-01-23 20:45:24.946984407 -0600
+++ b/drivers/bluetooth/ath3k.c 2013-01-23 20:45:51.443693307 -0600
@@ -68,6 +68,7 @@ static struct usb_device_id ath3k_table[
{ USB_DEVICE(0x0930, 0x0215) },
{ USB_DEVICE(0x0489, 0xE03D) },
{ USB_DEVICE(0x0489, 0xE027) },
+ { USB_DEVICE(0x04f2, 0xaff1) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
diff -uprN a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
--- a/drivers/bluetooth/btusb.c 2013-01-23 20:45:24.946984407 -0600
+++ b/drivers/bluetooth/btusb.c 2013-01-23 20:45:51.443693307 -0600
@@ -125,6 +125,7 @@ static struct usb_device_id blacklist_ta
{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x04f2, 0xaff1), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
My apologies if this is not the correct way to submit a patch.
[-- Attachment #2: Type: text/html, Size: 1861 bytes --]
^ permalink raw reply
* pull request: bluetooth-next 2013-01-24
From: Gustavo Padovan @ 2013-01-24 3:10 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, linux-bluetooth, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 3984 bytes --]
Hi John,
This is my first pull request to 3.9. The biggest changes here are from Johan
Hedberg who made a lot of fixes in the Management interface. The issues arose
due to a new test tool we wrote and the usage of the Management interface as
default in BlueZ 5. The rest of the patches are more clean ups and small
fixes.
Please pull! Thanks!
Gustavo
---
The following changes since commit e7f767a7d9f809c494bfffffeda2bbdbfec110b4:
mwifiex: use map/unmap APIs in TX and RX to reduce memcpy (2013-01-07 15:18:30 -0500)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next for-upstream
for you to fetch changes up to 9b008c0457e583e10e62d1215bed6ab26ee54906:
Bluetooth: Add support for reading LE supported states (2013-01-23 02:09:16 -0200)
----------------------------------------------------------------
Andrei Emeltchenko (4):
Bluetooth: AMP: Send A2MP Create Phylink Rsp after Assoc write
Bluetooth: AMP: Clean up logical link create / accept
Bluetooth: AMP: Remove dead code
Bluetooth: AMP: Use set_bit / test_bit for amp_mgr state
Gustavo Padovan (1):
Bluetooth: Fix uuid output in debugfs
Johan Hedberg (25):
Bluetooth: Fix missing command complete event for mgmt_confirm_name
Bluetooth: Fix missing command complete for mgmt_load_long_term_keys
Bluetooth: Fix checking for valid device class values
Bluetooth: Fix accepting set_dev_class for non-BR/EDR controllers
Bluetooth: Move non-critical sections outside of the dev lock
Bluetooth: Fix checking for exact values of boolean mgmt parameters
Bluetooth: Fix returning proper command status for start_discovery
Bluetooth: Fix sending incorrect new_settings for mgmt_set_powered
Bluetooth: Add a new workqueue for hci_request operations
Bluetooth: Use req_workqueue for hci_request operations
Bluetooth: Fix using system-global workqueue when not necessary
Bluetooth: Fix Class of Device indication when powering off
Bluetooth: Fix checking for correct mgmt_load_link_keys parameters
Bluetooth: Fix returning proper mgmt status for Load LTKs
Bluetooth: Fix checking for proper key->master value in Load LTKs
Bluetooth: Refactor valid LTK data testing into its own function
Bluetooth: Check for valid key->authenticated value for LTKs
Bluetooth: Add helper functions for testing bdaddr types
Bluetooth: Fix checking for valid address type values in mgmt commands
Bluetooth: Fix checking for valid disconnect parameters in unpair_device
Bluetooth: Fix returning proper cmd_complete for mgmt_disconnect
Bluetooth: Fix returning proper cmd_complete for mgmt_block/unblock
Bluetooth: Add LE Local Features reading support
Bluetooth: Add support for reading LE White List Size
Bluetooth: Add support for reading LE supported states
Rami Rosen (2):
Bluetooth: Remove unnecessary include l2cap.h
Bluetooth: remove an unused variable in a header file
Szymon Janc (3):
Bluetooth: mgmt: Remove not needed restriction on add/remove OOB data
Bluetooth: mgmt: Avoid using magic number in status code
Bluetooth: Fix pair device command reply if adapter is powered off
include/net/bluetooth/a2mp.h | 4 +-
include/net/bluetooth/bluetooth.h | 23 ++++
include/net/bluetooth/hci.h | 18 +++
include/net/bluetooth/hci_core.h | 4 +
include/net/bluetooth/l2cap.h | 1 -
net/bluetooth/a2mp.c | 42 ++++++-
net/bluetooth/amp.c | 25 ++--
net/bluetooth/bnep/core.c | 1 -
net/bluetooth/hci_core.c | 20 ++-
net/bluetooth/hci_event.c | 60 +++++++++
net/bluetooth/hci_sysfs.c | 22 ++--
net/bluetooth/l2cap_core.c | 5 -
net/bluetooth/mgmt.c | 270 ++++++++++++++++++++++++++++------------
13 files changed, 375 insertions(+), 120 deletions(-)
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix Class of Device indication when powering off
From: Gustavo Padovan @ 2013-01-23 4:20 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358345734-17892-1-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
* Johan Hedberg <johan.hedberg@gmail.com> [2013-01-16 16:15:34 +0200]:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> When a HCI device is powered off the Management interface specification
> dictates that the class of device value is indicated as zero. This patch
> fixes sending of the appropriate class of device changed event when a
> HCI device is powered off.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/mgmt.c | 6 ++++++
> 1 file changed, 6 insertions(+)
Patch has been applied to bluetooth-next. Thanks.
Gustavo
^ permalink raw reply
* Re: [PATCH 3/3] Bluetooth: Add support for reading LE supported states
From: Gustavo Padovan @ 2013-01-23 4:12 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358856121-1928-3-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
* Johan Hedberg <johan.hedberg@gmail.com> [2013-01-22 14:02:01 +0200]:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> The LE supported states indicate the states and state combinations that
> the link layer supports. This is important information for knowing what
> operations are possible when dealing with multiple connected devices.
> This patch adds reading of the supported states to the HCI init
> sequence.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> include/net/bluetooth/hci.h | 6 ++++++
> include/net/bluetooth/hci_core.h | 1 +
> net/bluetooth/hci_event.c | 20 ++++++++++++++++++++
> 3 files changed, 27 insertions(+)
All 3 patches have been applied. Thanks.
Gustavo
^ permalink raw reply
* Re: [PATCH 10/10 v2] Bluetooth: Fix returning proper cmd_complete for mgmt_block/unblock
From: Gustavo Padovan @ 2013-01-23 4:07 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358684842-4441-11-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
* Johan Hedberg <johan.hedberg@gmail.com> [2013-01-20 14:27:22 +0200]:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> The Block/Unblock Device Management commands should return Command
> Complete instead of Command Status whenever possible so that user space
> can distinguish exactly which command failed in the case of multiple
> commands. This patch does the necessary changes in the command handler
> to return the right event to user space.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/mgmt.c | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
All 10 patches have been applied to bluetooth-next. Thanks.
Gustavo
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix pair device command reply if adapter is powered off
From: Gustavo Padovan @ 2013-01-23 3:45 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1358509687-7194-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
* Szymon Janc <szymon.janc@tieto.com> [2013-01-18 12:48:07 +0100]:
> According to Bluetooth Management API specification Pair Device Command
> should generate command complete event on both success and failure.
> This fix replying with command status (which lacks address info) when
> adapter is powered off.
>
> Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
> ---
> net/bluetooth/mgmt.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
Patch has been applied to bluetooth-next. Thanks.
Gustavo
^ permalink raw reply
* Re: Thoughts about LE scanning
From: Andre Guedes @ 2013-01-23 1:12 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1358460154.2089.14.camel@aeonflux>
Hi Marcel,
On Thu, Jan 17, 2013 at 7:02 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hello,
>
> so I have been looking into how we handle LE scanning in central role a
> little bit. And I am not really happy with what we do right now. Instead
> of just adding new profiles, we need to take one step back and get the
> basics right.
>
> The one thing that I stumbled about is that we are trying to use the
> Start Discovery management command to scan for connectable device that
> we are paired with. And it is all triggered by bluetoothd. It tries to
> get this done right, but fails badly at it. Trying to do this ends up in
> a convoluted solution that will just break down eventually.
>
> So Start Discovery and Stop Discovery management commands are for
> finding new devices. They are for finding devices that we want to pair
> with. They are not for checking if a paired device is in range or
> signals connection requests to us. It is called discovery for a reason.
>
> It might have looked like a good idea to just re-use these two commands,
> but what I am seeing when working with multiple paired LE devices is
> just a big mess. The amount of code that is needed to keep track of
> states between running D-Bus commands for discovery, discovery triggered
> management commands, scanning triggered management commands etc. is not
> a good idea.
>
> I am failing to understand why we tried to solve this inside bluetoothd
> and not just let the kernel take full control here. We are loading the
> list of paired LE devices at controller power on anyway. So the kernel
> does know about our paired devices. It can control sensible scan
> intervals and also sync a device discovery with scanning for connection
> triggers from know remote devices. It also can sensible disconnect on
> idle and scan for other devices that requests connections.
We are working on moving this connection management into kernel space
and we should start sending RFCs soon.
> What I think we should have is a management command that allows us to
> load device specific scan parameter configuration into the kernel. And
> then the kernel will execute this on our behalf. We need to decouple the
> commands for device discovery from the commands that scan for known
> devices.
Once we have the connection management working properly we can working
on this new management command to setup the scan parameters.
Regards,
Andre
^ permalink raw reply
* Re: [PATCH BlueZ 2/2] avctp: Receive and silent ignore Vol Up/Down operations
From: Joao Paulo Rechi Vita @ 2013-01-22 19:09 UTC (permalink / raw)
To: Vinicius Costa Gomes
Cc: linux-bluetooth@vger.kernel.org, Luiz Augusto von Dentz
In-Reply-To: <20130122185650.GA1119@samus>
On Tue, Jan 22, 2013 at 3:56 PM, Vinicius Costa Gomes
<vinicius.gomes@openbossa.org> wrote:
> Hi Joao,
>
> On 15:18 Tue 22 Jan, João Paulo Rechi Vita wrote:
>> The AVRCP spec mandates to support 'volume up' and 'volume down'
>> operations when claiming support for Category 2 TG.
>> ---
>> profiles/audio/avctp.c | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
>> index f7e607e..4ab6d6d 100644
>> --- a/profiles/audio/avctp.c
>> +++ b/profiles/audio/avctp.c
>> @@ -214,6 +214,8 @@ static struct {
>> uint8_t avc;
>> uint16_t uinput;
>> } key_map[] = {
>> + { "VOLUME UP", AVC_VOLUME_UP, KEY_VOLUMEUP},
>> + { "VOLUME DOWN", AVC_VOLUME_DOWN, KEY_VOLUMEDOWN},
>> { "PLAY", AVC_PLAY, KEY_PLAYCD },
>> { "STOP", AVC_STOP, KEY_STOPCD },
>> { "PAUSE", AVC_PAUSE, KEY_PAUSECD },
>> @@ -968,6 +970,9 @@ static void init_uinput(struct avctp *session)
>>
>> dev = manager_get_audio_device(session->device, FALSE);
>>
>> + session->key_quirks[AVC_VOLUME_UP] |= QUIRK_IGNORE;
>> + session->key_quirks[AVC_VOLUME_DOWN] |= QUIRK_IGNORE;
>> +
>
> Having a quirk that applies to every device, doesn't seem to map to the
> meaning of 'quirk', i.e. if everybody has the same quirk, it is the norm ;-)
>
It is not a _device quirk_ but it is still a _key quirk_, that is, a
special behavior to handle that key. I could also have checked
specifically for the key id, but I find clearer to do it this way.
--
João Paulo Rechi Vita
Openbossa Labs - INdT
^ permalink raw reply
* Re: [PATCH BlueZ 2/2] avctp: Receive and silent ignore Vol Up/Down operations
From: Vinicius Costa Gomes @ 2013-01-22 18:56 UTC (permalink / raw)
To: João Paulo Rechi Vita; +Cc: linux-bluetooth, luiz.dentz
In-Reply-To: <1358878703-8100-3-git-send-email-jprvita@openbossa.org>
Hi Joao,
On 15:18 Tue 22 Jan, João Paulo Rechi Vita wrote:
> The AVRCP spec mandates to support 'volume up' and 'volume down'
> operations when claiming support for Category 2 TG.
> ---
> profiles/audio/avctp.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
> index f7e607e..4ab6d6d 100644
> --- a/profiles/audio/avctp.c
> +++ b/profiles/audio/avctp.c
> @@ -214,6 +214,8 @@ static struct {
> uint8_t avc;
> uint16_t uinput;
> } key_map[] = {
> + { "VOLUME UP", AVC_VOLUME_UP, KEY_VOLUMEUP},
> + { "VOLUME DOWN", AVC_VOLUME_DOWN, KEY_VOLUMEDOWN},
> { "PLAY", AVC_PLAY, KEY_PLAYCD },
> { "STOP", AVC_STOP, KEY_STOPCD },
> { "PAUSE", AVC_PAUSE, KEY_PAUSECD },
> @@ -968,6 +970,9 @@ static void init_uinput(struct avctp *session)
>
> dev = manager_get_audio_device(session->device, FALSE);
>
> + session->key_quirks[AVC_VOLUME_UP] |= QUIRK_IGNORE;
> + session->key_quirks[AVC_VOLUME_DOWN] |= QUIRK_IGNORE;
> +
Having a quirk that applies to every device, doesn't seem to map to the
meaning of 'quirk', i.e. if everybody has the same quirk, it is the norm ;-)
Cheers,
--
Vinicius
^ permalink raw reply
* [PATCH BlueZ 2/2] avctp: Receive and silent ignore Vol Up/Down operations
From: João Paulo Rechi Vita @ 2013-01-22 18:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, João Paulo Rechi Vita
In-Reply-To: <1358878703-8100-1-git-send-email-jprvita@openbossa.org>
The AVRCP spec mandates to support 'volume up' and 'volume down'
operations when claiming support for Category 2 TG.
---
profiles/audio/avctp.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
index f7e607e..4ab6d6d 100644
--- a/profiles/audio/avctp.c
+++ b/profiles/audio/avctp.c
@@ -214,6 +214,8 @@ static struct {
uint8_t avc;
uint16_t uinput;
} key_map[] = {
+ { "VOLUME UP", AVC_VOLUME_UP, KEY_VOLUMEUP},
+ { "VOLUME DOWN", AVC_VOLUME_DOWN, KEY_VOLUMEDOWN},
{ "PLAY", AVC_PLAY, KEY_PLAYCD },
{ "STOP", AVC_STOP, KEY_STOPCD },
{ "PAUSE", AVC_PAUSE, KEY_PAUSECD },
@@ -968,6 +970,9 @@ static void init_uinput(struct avctp *session)
dev = manager_get_audio_device(session->device, FALSE);
+ session->key_quirks[AVC_VOLUME_UP] |= QUIRK_IGNORE;
+ session->key_quirks[AVC_VOLUME_DOWN] |= QUIRK_IGNORE;
+
device_get_name(dev->btd_dev, name, sizeof(name));
if (g_str_equal(name, "Nokia CK-20W")) {
session->key_quirks[AVC_FORWARD] |= QUIRK_NO_RELEASE;
--
1.7.11.7
^ permalink raw reply related
* [PATCH BlueZ 1/2] avctp: Create ignore quirk
From: João Paulo Rechi Vita @ 2013-01-22 18:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, João Paulo Rechi Vita
In-Reply-To: <1358878703-8100-1-git-send-email-jprvita@openbossa.org>
Create a quirk to be able to accept and trow away certain keys.
---
profiles/audio/avctp.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
index 61890cc..f7e607e 100644
--- a/profiles/audio/avctp.c
+++ b/profiles/audio/avctp.c
@@ -58,7 +58,8 @@
#include "avctp.h"
#include "avrcp.h"
-#define QUIRK_NO_RELEASE 1 << 0
+#define QUIRK_NO_RELEASE 1 << 0
+#define QUIRK_IGNORE 1 << 1
/* Message types */
#define AVCTP_COMMAND 0
@@ -287,6 +288,11 @@ static size_t handle_panel_passthrough(struct avctp *session,
key_quirks = session->key_quirks[key_map[i].avc];
+ if (key_quirks & QUIRK_IGNORE) {
+ DBG("AV/C: ignoring %s %s", key_map[i].name, status);
+ break;
+ }
+
if (key_quirks & QUIRK_NO_RELEASE) {
if (!pressed) {
DBG("AV/C: Ignoring release");
--
1.7.11.7
^ permalink raw reply related
* [PATCH BlueZ 0/2] AVRCP: Add support for Vol Up/Down operations on TG
From: João Paulo Rechi Vita @ 2013-01-22 18:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, João Paulo Rechi Vita
This series creates a new quirk called QUIRK_IGNORE to be able to accept and
ignore certain keys. Then it uses this infrastructure to accept and ignore
Volume Up/Down operations, instead of replying with "Not Implemented".
Suport for Volume Up/Down is mandatory on TG side if we claim to support
Category 2 (Monitor / Amplifier). It's also tested by PTS on test
TC_TG_PTT_BV_02_I.
João Paulo Rechi Vita (2):
avctp: Create ignore quirk
avctp: Receive and silent ignore Vol Up/Down operations
profiles/audio/avctp.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
--
1.7.11.7
^ permalink raw reply
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