* [PATCH] bluetooth: btmrvl_sdio: look for sd8688 firmware in proper location
From: Lubomir Rintel @ 2013-01-18 7:37 UTC (permalink / raw)
To: Marcel Holtmann, Bing Zhao
Cc: Ben Hutchings, David Woodhouse, Gustavo Padovan, Johan Hedberg,
libertas-dev, linux-bluetooth, linux-kernel, Lubomir Rintel
In-Reply-To: <477F20668A386D41ADCC57781B1F70430D13FDB783@SC-VEXCH1.marvell.com>
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
drivers/bluetooth/btmrvl_sdio.c | 8 ++++----
drivers/bluetooth/btmrvl_sdio.h | 6 ++++--
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 3f4bfc8..bc27d01 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
- .helper = "sd8688_helper.bin",
- .firmware = "sd8688.bin",
+ .helper = "mrvl/sd8688_helper.bin",
+ .firmware = "mrvl/sd8688.bin",
.reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64,
};
@@ -1179,7 +1179,7 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("sd8688_helper.bin");
-MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
+MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 43d35a6..4a5a019 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -84,7 +84,9 @@ struct btmrvl_sdio_card {
struct sdio_func *func;
u32 ioport;
const char *helper;
+ const char *helper2;
const char *firmware;
+ const char *firmware2;
const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl;
u8 rx_unit;
@@ -92,8 +94,8 @@ struct btmrvl_sdio_card {
};
struct btmrvl_sdio_device {
- const char *helper;
- const char *firmware;
+ const char *helper, *helper2;
+ const char *firmware, *firmware2;
const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl;
};
--
1.7.1
^ permalink raw reply related
* [PATCH] libertas sdio: look for 8688 firmware in common location
From: Lubomir Rintel @ 2013-01-18 7:39 UTC (permalink / raw)
To: Dan Williams
Cc: Marcel Holtmann, Bing Zhao, Ben Hutchings, David Woodhouse,
Gustavo Padovan, Johan Hedberg, libertas-dev, linux-bluetooth,
linux-kernel, Lubomir Rintel
In-Reply-To: <1357771504.12030.59.camel@dcbw.foobar.com>
sd8688 is not only used by libertas WiFi, but shared with btmrvl bluetooth as
well.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
drivers/net/wireless/libertas/if_sdio.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 739309e..be16a76 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -85,6 +85,7 @@ static const struct lbs_fw_table fw_table[] = {
{ MODEL_8686, "libertas/sd8686_v9_helper.bin", "libertas/sd8686_v9.bin" },
{ MODEL_8686, "libertas/sd8686_v8_helper.bin", "libertas/sd8686_v8.bin" },
{ MODEL_8686, "sd8686_helper.bin", "sd8686.bin" },
+ { MODEL_8688, "mrvl/sd8688_helper.bin", "mrvl/sd8688.bin" },
{ MODEL_8688, "libertas/sd8688_helper.bin", "libertas/sd8688.bin" },
{ MODEL_8688, "sd8688_helper.bin", "sd8688.bin" },
{ 0, NULL, NULL }
@@ -99,6 +100,8 @@ MODULE_FIRMWARE("libertas/sd8686_v8_helper.bin");
MODULE_FIRMWARE("libertas/sd8686_v8.bin");
MODULE_FIRMWARE("sd8686_helper.bin");
MODULE_FIRMWARE("sd8686.bin");
+MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
+MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("libertas/sd8688_helper.bin");
MODULE_FIRMWARE("libertas/sd8688.bin");
MODULE_FIRMWARE("sd8688_helper.bin");
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] bluetooth: btmrvl_sdio: look for sd8688 firmware in proper location
From: Marcel Holtmann @ 2013-01-18 7:58 UTC (permalink / raw)
To: Lubomir Rintel
Cc: Bing Zhao, Ben Hutchings, David Woodhouse, Gustavo Padovan,
Johan Hedberg, libertas-dev, linux-bluetooth, linux-kernel
In-Reply-To: <1358494643-29765-1-git-send-email-lkundrak@v3.sk>
Hi Lubumir,
proper commit message with explanation here please.
> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
> ---
> drivers/bluetooth/btmrvl_sdio.c | 8 ++++----
> drivers/bluetooth/btmrvl_sdio.h | 6 ++++--
> 2 files changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
> index 3f4bfc8..bc27d01 100644
> --- a/drivers/bluetooth/btmrvl_sdio.c
> +++ b/drivers/bluetooth/btmrvl_sdio.c
> @@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
> };
>
> static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
> - .helper = "sd8688_helper.bin",
> - .firmware = "sd8688.bin",
> + .helper = "mrvl/sd8688_helper.bin",
> + .firmware = "mrvl/sd8688.bin",
> .reg = &btmrvl_reg_8688,
> .sd_blksz_fw_dl = 64,
> };
> @@ -1179,7 +1179,7 @@ MODULE_AUTHOR("Marvell International Ltd.");
> MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
> MODULE_VERSION(VERSION);
> MODULE_LICENSE("GPL v2");
> -MODULE_FIRMWARE("sd8688_helper.bin");
> -MODULE_FIRMWARE("sd8688.bin");
> +MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
> +MODULE_FIRMWARE("mrvl/sd8688.bin");
> MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
> MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
> diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
> index 43d35a6..4a5a019 100644
> --- a/drivers/bluetooth/btmrvl_sdio.h
> +++ b/drivers/bluetooth/btmrvl_sdio.h
> @@ -84,7 +84,9 @@ struct btmrvl_sdio_card {
> struct sdio_func *func;
> u32 ioport;
> const char *helper;
> + const char *helper2;
> const char *firmware;
> + const char *firmware2;
And please clear out the patch from left-overs.
> const struct btmrvl_sdio_card_reg *reg;
> u16 sd_blksz_fw_dl;
> u8 rx_unit;
> @@ -92,8 +94,8 @@ struct btmrvl_sdio_card {
> };
>
> struct btmrvl_sdio_device {
> - const char *helper;
> - const char *firmware;
> + const char *helper, *helper2;
> + const char *firmware, *firmware2;
And here as well.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH v2] core: Fix allow registering same custom property
From: Luiz Augusto von Dentz @ 2013-01-18 9:08 UTC (permalink / raw)
To: Frédéric Dalleau; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1358356034-2622-1-git-send-email-frederic.dalleau@linux.intel.com>
Hi Frederic,
On Wed, Jan 16, 2013 at 7:07 PM, Frédéric Dalleau
<frederic.dalleau@linux.intel.com> wrote:
> With several adapters, MediaEndpoint custom property is only created for the
> first adapter. When a new connection happens on another adapter
> btd_profile_custom_property_exists fails because the custom property doesn't
> exist for this last adapter. In case of HFP ofono fails with error: "Media
> Endpoint missing error".
>
> This patch allows the creation of several custom property with same name that
> can be distinguished based on a 'key'. When querying the property, additional
> checking must happen. For example endpoint_properties_exists, compares
> btd_adapter.
> 'NULL' key maintains existing behavior.
> ---
> profiles/audio/media.c | 5 +++--
> src/profile.c | 22 ++++++++++++++++------
> src/profile.h | 6 ++++--
> 3 files changed, 23 insertions(+), 10 deletions(-)
>
> diff --git a/profiles/audio/media.c b/profiles/audio/media.c
> index 4b91656..60a5da5 100644
> --- a/profiles/audio/media.c
> +++ b/profiles/audio/media.c
> @@ -195,7 +195,7 @@ static void media_endpoint_remove(struct media_endpoint *endpoint)
>
> if (media_adapter_find_endpoint(adapter, NULL, NULL,
> endpoint->uuid) == NULL)
> - btd_profile_remove_custom_prop(endpoint->uuid,
> + btd_profile_remove_custom_prop(adapter, endpoint->uuid,
> "MediaEndpoints");
>
> media_endpoint_destroy(endpoint);
> @@ -740,7 +740,8 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
> endpoint, NULL);
>
> if (media_adapter_find_endpoint(adapter, NULL, NULL, uuid) == NULL) {
> - btd_profile_add_custom_prop(uuid, "a{sv}", "MediaEndpoints",
> + btd_profile_add_custom_prop(adapter, uuid, "a{sv}",
> + "MediaEndpoints",
> endpoint_properties_exists,
> endpoint_properties_get,
> adapter);
> diff --git a/src/profile.c b/src/profile.c
> index b0c8500..7d48cfc 100644
> --- a/src/profile.c
> +++ b/src/profile.c
> @@ -572,6 +572,7 @@ struct ext_record {
> };
>
> struct btd_profile_custom_property {
> + const void *key;
> char *uuid;
> char *type;
> char *name;
> @@ -2208,7 +2209,8 @@ static const GDBusMethodTable methods[] = {
> { }
> };
>
> -static struct btd_profile_custom_property *find_custom_prop(const char *uuid,
> +static struct btd_profile_custom_property *find_custom_prop(const char *key,
> + const char *uuid,
> const char *name)
> {
> GSList *l;
> @@ -2216,6 +2218,9 @@ static struct btd_profile_custom_property *find_custom_prop(const char *uuid,
> for (l = custom_props; l; l = l->next) {
> struct btd_profile_custom_property *prop = l->data;
>
> + if (prop->key != key)
> + continue;
> +
> if (strcasecmp(prop->uuid, uuid) != 0)
> continue;
>
> @@ -2226,7 +2231,8 @@ static struct btd_profile_custom_property *find_custom_prop(const char *uuid,
> return NULL;
> }
>
> -bool btd_profile_add_custom_prop(const char *uuid, const char *type,
> +bool btd_profile_add_custom_prop(const void *key, const char *uuid,
> + const char *type,
> const char *name,
> btd_profile_prop_exists exists,
> btd_profile_prop_get get,
> @@ -2234,12 +2240,15 @@ bool btd_profile_add_custom_prop(const char *uuid, const char *type,
> {
> struct btd_profile_custom_property *prop;
>
> - prop = find_custom_prop(uuid, name);
> - if (prop != NULL)
> + prop = find_custom_prop(key, uuid, name);
> + if (prop != NULL) {
> + DBG("Custom property %s already exists", name);
> return false;
> + }
>
> prop = g_new0(struct btd_profile_custom_property, 1);
>
> + prop->key = key;
> prop->uuid = g_strdup(uuid);
> prop->type = g_strdup(type);
> prop->name = g_strdup(name);
> @@ -2263,11 +2272,12 @@ static void free_property(gpointer data)
> g_free(p);
> }
>
> -bool btd_profile_remove_custom_prop(const char *uuid, const char *name)
> +bool btd_profile_remove_custom_prop(const void *key, const char *uuid,
> + const char *name)
> {
> struct btd_profile_custom_property *prop;
>
> - prop = find_custom_prop(uuid, name);
> + prop = find_custom_prop(key, uuid, name);
> if (prop == NULL)
> return false;
>
> diff --git a/src/profile.h b/src/profile.h
> index d858925..0764f6f 100644
> --- a/src/profile.h
> +++ b/src/profile.h
> @@ -67,12 +67,14 @@ typedef bool (*btd_profile_prop_get)(const char *uuid,
> DBusMessageIter *iter,
> void *user_data);
>
> -bool btd_profile_add_custom_prop(const char *uuid, const char *type,
> +bool btd_profile_add_custom_prop(const void *key, const char *uuid,
> + const char *type,
> const char *name,
> btd_profile_prop_exists exists,
> btd_profile_prop_get get,
> void *user_data);
> -bool btd_profile_remove_custom_prop(const char *uuid, const char *name);
> +bool btd_profile_remove_custom_prop(const void *key, const char *uuid,
> + const char *name);
>
> void btd_profile_init(void);
> void btd_profile_cleanup(void);
> --
> 1.7.9.5
Im afraid you are trying to fix in the wrong place, indeed there is a
problem when a custom property is already registered it cannot
register another time for a different adapter, but what we should be
doing is checking the list of adapters in endpoint_properties_exists,
you just have to find by btd_adapter instead of using user_data for
that, in fact the user_data should be probably NULL as we have the
list of adapters global in media.c
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH] Bluetooth: Fix pair device command reply if adapter is powered off
From: Szymon Janc @ 2013-01-18 11:48 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
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(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fc171f2..3aa8c38 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1939,11 +1939,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
+ memset(&rp, 0, sizeof(rp));
+ bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+ rp.addr.type = cp->addr.type;
+
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
- MGMT_STATUS_NOT_POWERED);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+ MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
goto unlock;
}
@@ -1960,10 +1964,6 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
cp->addr.type, sec_level, auth_type);
- memset(&rp, 0, sizeof(rp));
- bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
- rp.addr.type = cp->addr.type;
-
if (IS_ERR(conn)) {
int status;
--
1.8.0.3
^ permalink raw reply related
* [PATCH 1/2] tools: Add mgmt test case for pair device while powered off
From: Szymon Janc @ 2013-01-18 11:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This tests if kernel is responding with proper command complete event.
---
tools/mgmt-tester.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index cb02480..5c72d00 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -916,6 +916,20 @@ static const struct generic_data add_uuid32_test_1 = {
.expect_hci_len = sizeof(write_eir_uuid32_hci),
};
+static const char pair_device_param[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00 };
+static const char pair_device_rsp[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 };
+
+static const struct generic_data pair_device_not_powered_test_1 = {
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_param = pair_device_param,
+ .send_len = sizeof(pair_device_param),
+ .expect_status = MGMT_STATUS_NOT_POWERED,
+ .expect_param = pair_device_rsp,
+ .expect_len = sizeof(pair_device_rsp),
+};
+
static void setup_powered_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -1414,5 +1428,8 @@ int main(int argc, char *argv[])
test_bredr("Add UUID - UUID-32 1", &add_uuid32_test_1, setup_ssp,
test_command_generic);
+ test_bredr("Pair Device - Not Powered 1",
+ &pair_device_not_powered_test_1, NULL,
+ test_command_generic);
return tester_run();
}
--
1.8.0.3
^ permalink raw reply related
* [PATCH 2/2] Adapter: Add workaround for device pairing kernel bug
From: Szymon Janc @ 2013-01-18 11:51 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1358509895-7460-1-git-send-email-szymon.janc@tieto.com>
Some kernels reply to device pairing command with bogus command status
instead of command complete event if adapter was not powered.
Command status event doesn't provide remote device address and type
needed to properly complete bonding request.
Pass possibly missing data as user_data to mgmt_send and use it in
pair_device_complete function if needed.
---
src/adapter.c | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 1a5b1ad..c413242 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -4643,17 +4643,40 @@ static void adapter_bonding_complete(struct btd_adapter *adapter,
check_oob_bonding_complete(adapter, bdaddr, status);
}
+struct pair_device_data {
+ struct btd_adapter *adapter;
+ bdaddr_t bdaddr;
+ uint8_t addr_type;
+};
+
+static void free_pair_device_data(void *user_data)
+{
+ struct pair_device_data *data = user_data;
+
+ g_free(data);
+}
+
static void pair_device_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
const struct mgmt_rp_pair_device *rp = param;
- struct btd_adapter *adapter = user_data;
+ struct pair_device_data *data = user_data;
DBG("%s (0x%02x)", mgmt_errstr(status), status);
+ /*
+ * Workaround for a kernel bug
+ *
+ * Broken kernels may reply to device pairing command with command
+ * status instead of command complete event e.g. if adapter was not
+ * powered.
+ */
if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
error("Pair device failed: %s (0x%02x)",
mgmt_errstr(status), status);
+
+ adapter_bonding_complete(data->adapter, &data->bdaddr,
+ data->addr_type, status);
return;
}
@@ -4662,7 +4685,7 @@ static void pair_device_complete(uint8_t status, uint16_t length,
return;
}
- adapter_bonding_complete(adapter, &rp->addr.bdaddr, rp->addr.type,
+ adapter_bonding_complete(data->adapter, &rp->addr.bdaddr, rp->addr.type,
status);
}
@@ -4671,6 +4694,7 @@ int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
{
struct mgmt_cp_pair_device cp;
char addr[18];
+ struct pair_device_data *data;
suspend_discovery(adapter);
@@ -4683,13 +4707,21 @@ int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
cp.addr.type = addr_type;
cp.io_cap = io_cap;
+ data = g_new0(struct pair_device_data, 1);
+ data->adapter = adapter;
+ bacpy(&data->bdaddr, bdaddr);
+ data->addr_type = addr_type;
+
if (mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE,
adapter->dev_id, sizeof(cp), &cp,
- pair_device_complete, adapter, NULL) > 0)
+ pair_device_complete, data,
+ free_pair_device_data) > 0)
return 0;
error("Failed to pair %s for hci%u", addr, adapter->dev_id);
+ free_pair_device_data(data);
+
return -EIO;
}
--
1.8.0.3
^ permalink raw reply related
* Auto reconnect heartrate LE device
From: Damjan Cvetko @ 2013-01-18 12:06 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
Hi.
Talked to jhe on IRC regarding this some days ago. I have a Polar heart rate monitor, and with the latest code it work well enough. However when the device goes out of range, it is disconnected from bluetoothd and does not reconnect when coming back into range:
bluetoothd[2898]: src/adapter.c:dev_disconnected() Device 00:22:D0:00:00:64 disconnected, reason 0
...
bluetoothd[2898]: src/device.c:attrib_disconnected_cb() Automatic connection disabled
I wanted to add auto reconnection, and this 1 line fix is what I came up with. It works in most cases, but sometimes bluetoothd fals into a loop.
...
"src/adapter.c:adapter_set_discovering() hci0 restarting discovery: disc_sessions 2"
"src/adapter.c:start_discovery_complete() Busy (0x0a)"
"src/adapter.c:adapter_set_discovering() hci0 restarting discovery: disc_sessions 2"
...
Still looking into that part, could also be unrelated. Here is the patch.
Best,
Damjan
---
Set auto connect for heartrate device.
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 5c56d3f..1788d4f 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -801,6 +801,8 @@ static int heartrate_device_register(struct btd_device *device,
hr->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
attio_disconnected_cb, hr);
+ device_set_auto_connect(device, TRUE);
+
return 0;
}
^ permalink raw reply related
* Re: [PATCH 0/5] MAP client: Add missing parameters for GetMessageListing
From: Luiz Augusto von Dentz @ 2013-01-18 12:12 UTC (permalink / raw)
To: Christian Fetzer; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1358258204-4090-1-git-send-email-christian.fetzer@oss.bmw-carit.de>
Hi Christian,
On Tue, Jan 15, 2013 at 3:56 PM, Christian Fetzer
<christian.fetzer@oss.bmw-carit.de> wrote:
> From: Christian Fetzer <christian.fetzer@bmw-carit.de>
>
> This patchset adds the missing parameters Text, AttachmentSize and Status
> as well as the filter SubjectLength.
>
> Christian Fetzer (5):
> obexd: Add parameter SubjectLength to map_list_messages
> obexd: Move parse_size function in map.c
> obexd: Add parameter Text to GetMessageListing response
> obexd: Add parameter AttachmentSize to GetMessageListing response
> obexd: Add parameter Status to GetMessageListing response
>
> doc/obex-api.txt | 20 +++++++++++--
> obexd/client/map.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++---
> 2 files changed, 101 insertions(+), 6 deletions(-)
>
> --
> 1.8.1
All 5 patches have been pushed upstream, just need to do a minor fix
to SubjectLength type since D-Bus don't really have uint8 I modified
it to byte.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix pair device command reply if adapter is powered off
From: Johan Hedberg @ 2013-01-18 12:35 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1358509687-7194-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Fri, Jan 18, 2013, Szymon Janc wrote:
> 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(-)
Acked-by: Johan Hedberg <johan.hedberg@intel.com>
Johan
^ permalink raw reply
* RE: bluez: atomic operations
From: Kling, Andreas @ 2013-01-18 12:51 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1358400337.3059.11.camel@aeonflux>
Hi Marcel
>Hi Andy,
>
>> using gcc atomic buildins breaks support for older gcc/platforms.
>>
>> src/bluetoothd-adapter.o: In function `btd_adapter_unref':
>> adapter.c:(.text+0x63f8): undefined reference to `__sync_sub_and_fetch_4=
'
>>
>> I suggest to use glib g_atomic_* group of functions.
>> They fall back to traditional locking if buildins are not available.
>
>the GLib atomic API functions are not really stable. The GLib people for
>some reason decided to break their own API/ABI guarantee. So we moved
>away from using them. And I have no intention to get back to them.
>
>Long term, we are moving away from GLib and want to switch to ELL. So
>that means gcc atomics are required. My advise would be to get a modern
>platform and not rely on workarounds.
>
>Regards
>
>Marcel
many thanks for your answer.
unfortunately a modern platform is not an option for me, hopefully changes =
some day.
so I will maintain another local patch (yieha) :P
ELL? sounds interesting... will have a look at it.
regards
andy=
^ permalink raw reply
* [PATCH 00/10] Bluetooth: Fix more mgmt parameter checks
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
Hi,
This patch set is intended to be applied after Szymon's "Bluetooth: Fix
pair device command reply if adapter is powered off" patch.
This set includes fixes to improve the validity checks on parameters we
receive from user space in mgmt commands. Each of these fixes has had
its own test case added to the user space mgmt-tester and has been
verified to work.
Johan
^ permalink raw reply
* [PATCH 01/10] Bluetooth: Fix checking for correct mgmt_load_link_keys parameters
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The debug_keys parameter is only allowed to have the values 0x00 and
0x01. Any other value should result in a proper command status with
MGMT_STATUS_INVALID_PARAMS.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 36b2310..d9b042e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1519,6 +1519,10 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
MGMT_STATUS_INVALID_PARAMS);
}
+ if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
+ return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+ MGMT_STATUS_INVALID_PARAMS);
+
BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
key_count);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 02/10] Bluetooth: Fix returning proper mgmt status for Load LTKs
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
Failures of mgmt commands should be indicated with valid mgmt status
codes, and EINVAL is not one of them. Instead MGMT_STATUS_INVALID_PARAMS
should be returned.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.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 d9b042e..a050eee 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2716,7 +2716,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
BT_ERR("load_keys: expected %u bytes, got %u bytes",
len, expected_len);
return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
- EINVAL);
+ MGMT_STATUS_INVALID_PARAMS);
}
BT_DBG("%s key_count %u", hdev->name, key_count);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 03/10] Bluetooth: Fix checking for proper key->master value in Load LTKs
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The allowed values for the key->master parameter in the Load LTKs
command are 0x00 and 0x01. If there is a key in the list with some other
value the command should fail with a proper invalid params response.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a050eee..5388151 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2729,6 +2729,14 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
struct mgmt_ltk_info *key = &cp->keys[i];
u8 type;
+ if (key->master != 0x00 && key->master != 0x01) {
+ hci_smp_ltks_clear(hdev);
+ err = cmd_status(sk, hdev->id,
+ MGMT_OP_LOAD_LONG_TERM_KEYS,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (key->master)
type = HCI_SMP_LTK;
else
@@ -2743,6 +2751,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
NULL, 0);
+unlock:
hci_dev_unlock(hdev);
return err;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 04/10] Bluetooth: Refactor valid LTK data testing into its own function
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch refactors valid LTK data testing into its own function. This
will help keep the code readable since there are several tests still
missing that need to be done on the LTK data.
---
net/bluetooth/mgmt.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5388151..3634907 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2701,6 +2701,13 @@ done:
return err;
}
+static bool ltk_is_valid(struct mgmt_ltk_info *key)
+{
+ if (key->master != 0x00 && key->master != 0x01)
+ return false;
+ return true;
+}
+
static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
void *cp_data, u16 len)
{
@@ -2729,7 +2736,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
struct mgmt_ltk_info *key = &cp->keys[i];
u8 type;
- if (key->master != 0x00 && key->master != 0x01) {
+ if (!ltk_is_valid(key)) {
hci_smp_ltks_clear(hdev);
err = cmd_status(sk, hdev->id,
MGMT_OP_LOAD_LONG_TERM_KEYS,
--
1.7.10.4
^ permalink raw reply related
* [PATCH 05/10] Bluetooth: Check for valid key->authenticated value for LTKs
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds necessary checks for the two allowed values of the
authenticated parameter of each Long Term Key, i.e. 0x00 and 0x01. If
any other value is encountered the valid response is to return invalid
params to user space.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3634907..76301a3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2703,6 +2703,8 @@ done:
static bool ltk_is_valid(struct mgmt_ltk_info *key)
{
+ if (key->authenticated != 0x00 && key->authenticated != 0x01)
+ return false;
if (key->master != 0x00 && key->master != 0x01)
return false;
return true;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 06/10] Bluetooth: Add helper functions for testing bdaddr types
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds two helper functions to test for valid bdaddr type
values. These will be particularely useful in the mgmt code to check
that user space has passed valid values to the kernel.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
include/net/bluetooth/bluetooth.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 2554b3f..9531bee 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -166,6 +166,29 @@ typedef struct {
#define BDADDR_LE_PUBLIC 0x01
#define BDADDR_LE_RANDOM 0x02
+static inline bool bdaddr_type_is_valid(__u8 type)
+{
+ switch (type) {
+ case BDADDR_BREDR:
+ case BDADDR_LE_PUBLIC:
+ case BDADDR_LE_RANDOM:
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool bdaddr_type_is_le(__u8 type)
+{
+ switch (type) {
+ case BDADDR_LE_PUBLIC:
+ case BDADDR_LE_RANDOM:
+ return true;
+ }
+
+ return false;
+}
+
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
--
1.7.10.4
^ permalink raw reply related
* [PATCH 07/10] Bluetooth: Fix checking for valid address type values in mgmt commands
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds checks for valid address type values passed to mgmt
commands. If an invalid address type is encountered the code will return
a proper invalid params response.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 43 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 76301a3..3de4bc2 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1506,7 +1506,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
{
struct mgmt_cp_load_link_keys *cp = data;
u16 key_count, expected_len;
- int i;
+ int i, err;
key_count = __le16_to_cpu(cp->key_count);
@@ -1540,15 +1540,24 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
for (i = 0; i < key_count; i++) {
struct mgmt_link_key_info *key = &cp->keys[i];
+ if (key->addr.type != BDADDR_BREDR) {
+ clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+ hci_link_keys_clear(hdev);
+ err = cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
key->type, key->pin_len);
}
- cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
+unlock:
hci_dev_unlock(hdev);
- return 0;
+ return err;
}
static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -1573,12 +1582,17 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
struct hci_conn *conn;
int err;
- hci_dev_lock(hdev);
-
memset(&rp, 0, sizeof(rp));
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
rp.addr.type = cp->addr.type;
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
+
+ hci_dev_lock(hdev);
+
if (!hdev_is_powered(hdev)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
@@ -1643,6 +1657,10 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_INVALID_PARAMS);
+
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
@@ -1947,6 +1965,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
rp.addr.type = cp->addr.type;
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
+
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
@@ -2564,6 +2587,10 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS);
+
hci_dev_lock(hdev);
err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
@@ -2589,6 +2616,10 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS);
+
hci_dev_lock(hdev);
err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
@@ -2707,6 +2738,8 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
return false;
if (key->master != 0x00 && key->master != 0x01)
return false;
+ if (!bdaddr_type_is_le(key->addr.type))
+ return false;
return true;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 08/10] Bluetooth: Fix checking for valid disconnect parameters in unpair_device
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The valid values for the Disconnect parameter in the Unpair Device
command are 0x00 and 0x01. If any other value is encountered the command
should fail with the appropriate invalid params response.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3de4bc2..8ec3c4f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1591,6 +1591,11 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
MGMT_STATUS_INVALID_PARAMS,
&rp, sizeof(rp));
+ if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
+
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
--
1.7.10.4
^ permalink raw reply related
* [PATCH 09/10] Bluetooth: Fix returning proper cmd_complete for mgmt_disconnect
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The Disconnect Management command 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 disconnect command handler to
return the right event to user space.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 8ec3c4f..184673e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1655,6 +1655,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_disconnect *cp = data;
+ struct mgmt_rp_disconnect rp;
struct hci_cp_disconnect dc;
struct pending_cmd *cmd;
struct hci_conn *conn;
@@ -1662,21 +1663,26 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
+ memset(&rp, 0, sizeof(rp));
+ bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+ rp.addr.type = cp->addr.type;
+
if (!bdaddr_type_is_valid(cp->addr.type))
- return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_INVALID_PARAMS);
+ return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_NOT_POWERED);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
goto failed;
}
if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_BUSY);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_BUSY, &rp, sizeof(rp));
goto failed;
}
@@ -1687,8 +1693,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_NOT_CONNECTED);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
goto failed;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 10/10] Bluetooth: Fix returning proper cmd_complete for mgmt_block/unblock
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
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(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 184673e..50daae8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2599,8 +2599,9 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
if (!bdaddr_type_is_valid(cp->addr.type))
- return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
+ return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &cp->addr, sizeof(cp->addr));
hci_dev_lock(hdev);
@@ -2628,8 +2629,9 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
if (!bdaddr_type_is_valid(cp->addr.type))
- return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &cp->addr, sizeof(cp->addr));
hci_dev_lock(hdev);
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH 1/2] tools: Add mgmt test case for pair device while powered off
From: Johan Hedberg @ 2013-01-18 13:26 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1358509895-7460-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Fri, Jan 18, 2013, Szymon Janc wrote:
> This tests if kernel is responding with proper command complete event.
> ---
> tools/mgmt-tester.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
Applied. Thanks.
Johan
^ permalink raw reply
* [PATCH BlueZ 1/2] tools: Make mpris-player to export players using MPRIS interface
From: Luiz Augusto von Dentz @ 2013-01-18 14:41 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.
---
tools/mpris-player.c | 798 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 779 insertions(+), 19 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 246791a..e3bab1c 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,30 @@
#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_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"
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 +208,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 +235,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 +244,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 +257,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 +280,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 +529,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 +568,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 +587,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 +629,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,21 +781,685 @@ 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 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)
+{
+ 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 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;
+ 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 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 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, 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, 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 },
+ { "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 },
+ { }
+};
+
+static const GDBusMethodTable mpris_methods[] = {
+ { }
+};
+
+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 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 },
+ { }
+};
+
+static char *mpris_busname(const char *name)
+{
+ char *bus_name;
+
+ bus_name = g_strconcat(MPRIS_BUS_NAME, name, NULL);
+ return g_strdelimit(bus_name, " ’", '_');
+}
+
+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(name);
+ player->proxy = g_dbus_proxy_ref(proxy);
+ player->device = device;
+
+ players = g_slist_prepend(players, player);
+
+ 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_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,
+ 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)
@@ -759,19 +1471,67 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
interface = g_dbus_proxy_get_interface(proxy);
- if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE))
+ 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;
+
+ player = find_player(proxy);
+ if (player == NULL)
+ return;
+
+ printf("Bluetooth Player %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_player(player);
+ }
+}
+
+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, "org.bluez.MediaPlayer1") != 0)
return;
- if (adapter != proxy)
+ player = find_player(proxy);
+ if (player == NULL)
return;
- printf("Bluetooth Adapter %s removed\n", g_dbus_proxy_get_path(proxy));
- adapter = NULL;
+ 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[])
{
- GDBusClient *client;
guint owner_watch, properties_watch;
struct sigaction sa;
int opt;
@@ -825,7 +1585,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.0.2
^ permalink raw reply related
* [PATCH BlueZ 2/2] tools: Add volume support for mpris-player
From: Luiz Augusto von Dentz @ 2013-01-18 14:41 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358520085-4790-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 e3bab1c..80bb76d 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);
@@ -1287,6 +1293,30 @@ static gboolean get_disable(const GDBusPropertyTable *property,
return TRUE;
}
+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) },
@@ -1311,7 +1341,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 },
@@ -1353,12 +1383,33 @@ static char *mpris_busname(const char *name)
return g_strdelimit(bus_name, " ’", '_');
}
+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;
@@ -1412,6 +1463,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:
@@ -1419,6 +1474,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;
@@ -1437,6 +1533,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);
}
}
@@ -1462,6 +1562,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;
@@ -1487,6 +1618,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);
}
}
@@ -1506,16 +1641,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, "org.bluez.MediaPlayer1") != 0)
- return;
+ const char *property;
player = find_player(proxy);
if (player == NULL)
@@ -1530,6 +1660,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.0.2
^ 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