* [PATCH 3/3] frame reassembly implementation for data from stream
From: suraj @ 2010-06-01 8:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, Luis.Rodriguez, Jothikumar.Mothilal
In-Reply-To: <1275379734.19477.14.camel@atheros013-desktop>
Implemented hci_recv_stream_fragment to reassemble HCI packets received from a data stream
with packet type not known.
Signed-off-by: suraj <suraj@Atheros.com>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 104 ++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 65c3c13..9892c26 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -429,6 +429,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
int hci_recv_packet_fragment(struct hci_dev *hdev, int type, void *data,
int count);
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e7ce432..1587dc8 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1033,6 +1033,110 @@ EXPORT_SYMBOL(hci_recv_frame);
/* Receive packet type fragment */
#define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2])
+#define __get_max_rx_size(type) \
+ (((type) == HCI_ACLDATA_PKT) ? \
+ HCI_MAX_FRAME_SIZE : \
+ ((type) == HCI_EVENT_PKT) ? HCI_MAX_EVENT_SIZE :\
+ HCI_MAX_SCO_SIZE)
+
+#define __get_header_len(type) \
+ (((type) == HCI_ACLDATA_PKT) ? \
+ HCI_ACL_HDR_SIZE : \
+ ((type) == HCI_EVENT_PKT) ? HCI_EVENT_HDR_SIZE :\
+ HCI_SCO_HDR_SIZE)
+
+/* Receive fragment from data streams */
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
+{
+ int type;
+
+ while (count) {
+ /*
+ * Reuse first pointer from reassembly array
+ */
+ struct sk_buff *skb = __reassembly(hdev, HCI_ACLDATA_PKT);
+
+ struct { int expect; int pkt_type; } *scb;
+ int len = 0;
+
+ if (!skb) {
+ struct { char type; } *pkt;
+
+ /* Start of the frame */
+ pkt = data;
+ type = pkt->type;
+
+ if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+ return -EILSEQ;
+
+ len = __get_max_rx_size(type);
+
+ skb = bt_skb_alloc(len, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ scb = (void *) skb->cb;
+ scb->expect = __get_header_len(type);
+ scb->pkt_type = type;
+
+ skb->dev = (void *) hdev;
+ __reassembly(hdev, HCI_ACLDATA_PKT) = skb;
+
+ data++;
+ count--;
+
+ continue;
+ } else {
+ /* Continue of frame */
+ scb = (void *) skb->cb;
+ len = min(scb->expect, count);
+ type = scb->pkt_type;
+
+ memcpy(skb_put(skb, len), data, len);
+
+ count -= len;
+ data += len;
+ scb->expect -= len;
+ }
+
+ switch (type) {
+ case HCI_EVENT_PKT:
+ if (skb->len == HCI_EVENT_HDR_SIZE) {
+ struct hci_event_hdr *h = hci_event_hdr(skb);
+ scb->expect = h->plen;
+ }
+ break;
+
+ case HCI_ACLDATA_PKT:
+ if (skb->len == HCI_ACL_HDR_SIZE) {
+ struct hci_acl_hdr *h = hci_acl_hdr(skb);
+ scb->expect = __le16_to_cpu(h->dlen);
+ }
+ break;
+
+ case HCI_SCODATA_PKT:
+ if (skb->len == HCI_SCO_HDR_SIZE) {
+ struct hci_sco_hdr *h = hci_sco_hdr(skb);
+ scb->expect = h->dlen;
+ }
+ break;
+ }
+
+ if (scb->expect == 0) {
+ /* Complete frame */
+
+ __reassembly(hdev, HCI_ACLDATA_PKT) = NULL;
+
+ bt_cb(skb)->pkt_type = type;
+ hci_recv_frame(skb);
+ }
+
+ }
+ return 0;
+}
+EXPORT_SYMBOL(hci_recv_stream_fragment);
+
+/* Receive packet fragment with known packet type */
int hci_recv_packet_fragment(struct hci_dev *hdev, int type, void *data,
int count)
{
--
1.7.0
^ permalink raw reply related
* RE: [PATCH 2/3] Replace hci_recv_fragment calls
From: Luis Rodriguez @ 2010-06-01 14:29 UTC (permalink / raw)
To: Suraj Sumangala, linux-bluetooth@vger.kernel.org
Cc: marcel@holtmann.org, Jothikumar Mothilal
In-Reply-To: <1275379734.19477.14.camel@atheros013-desktop>
You want to unify patches 1 and 2. Patches upstream should be atomic so tha=
t if you apply it, it should make everything still work. Your first patch =
removes hci_recv_fragment() and then this one fixes the places that call it=
, you want to do both in one shot.
Luis
________________________________________
From: Suraj Sumangala
Sent: Tuesday, June 01, 2010 1:08 AM
To: linux-bluetooth@vger.kernel.org
Cc: marcel@holtmann.org; Luis Rodriguez; Jothikumar Mothilal
Subject: [PATCH 2/3] Replace hci_recv_fragment calls
Replace all usages of hci_recv_fragment calls with
hci_recv_packet_fragment
Signed-off-by: suraj <suraj@Atheros.com>
---
drivers/bluetooth/btusb.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 5d9cc53..50aa8d1 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -211,7 +211,7 @@ static void btusb_intr_complete(struct urb *urb)
if (urb->status =3D=3D 0) {
hdev->stat.byte_rx +=3D urb->actual_length;
- if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
+ if (hci_recv_packet_fragment(hdev, HCI_EVENT_PKT,
urb->transfer_buffer,
urb->actual_length) < 0) {
BT_ERR("%s corrupted event packet", hdev->name);
@@ -295,7 +295,7 @@ static void btusb_bulk_complete(struct urb *urb)
if (urb->status =3D=3D 0) {
hdev->stat.byte_rx +=3D urb->actual_length;
- if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
+ if (hci_recv_packet_fragment(hdev, HCI_ACLDATA_PKT,
urb->transfer_buffer,
urb->actual_length) < 0) {
BT_ERR("%s corrupted ACL packet", hdev->name);
@@ -384,7 +384,7 @@ static void btusb_isoc_complete(struct urb *urb)
hdev->stat.byte_rx +=3D length;
- if (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
+ if (hci_recv_packet_fragment(hdev, HCI_SCODATA_PKT,
urb->transfer_buffer + offs=
et,
length) < 0=
) {
BT_ERR("%s corrupted SCO packet", hdev->nam=
e);
--
1.7.0
^ permalink raw reply related
* [PATCH v3] Change MDP profile name and macros to HDP
From: Elvis Pfützenreuter @ 2010-06-01 19:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: epx
---
lib/sdp.c | 6 +++---
lib/sdp.h | 22 ++++++++++++++++------
tools/sdptool.c | 6 +++---
3 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/lib/sdp.c b/lib/sdp.c
index aa22c63..ca3b4c4 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -201,9 +201,9 @@ static struct tupla ServiceClass[] = {
{ VIDEO_SOURCE_SVCLASS_ID, "Video Source" },
{ VIDEO_SINK_SVCLASS_ID, "Video Sink" },
{ VIDEO_DISTRIBUTION_SVCLASS_ID, "Video Distribution" },
- { MDP_SVCLASS_ID, "MDP" },
- { MDP_SOURCE_SVCLASS_ID, "MDP Source" },
- { MDP_SINK_SVCLASS_ID, "MDP Sink" },
+ { HDP_SVCLASS_ID, "HDP" },
+ { HDP_SOURCE_SVCLASS_ID, "HDP Source" },
+ { HDP_SINK_SVCLASS_ID, "HDP Sink" },
{ APPLE_AGENT_SVCLASS_ID, "Apple Agent" },
{ 0 }
};
diff --git a/lib/sdp.h b/lib/sdp.h
index a33e0a8..909bb02 100644
--- a/lib/sdp.h
+++ b/lib/sdp.h
@@ -140,9 +140,9 @@ extern "C" {
#define VIDEO_SOURCE_SVCLASS_ID 0x1303
#define VIDEO_SINK_SVCLASS_ID 0x1304
#define VIDEO_DISTRIBUTION_SVCLASS_ID 0x1305
-#define MDP_SVCLASS_ID 0x1400
-#define MDP_SOURCE_SVCLASS_ID 0x1401
-#define MDP_SINK_SVCLASS_ID 0x1402
+#define HDP_SVCLASS_ID 0x1400
+#define HDP_SOURCE_SVCLASS_ID 0x1401
+#define HDP_SINK_SVCLASS_ID 0x1402
#define APPLE_AGENT_SVCLASS_ID 0x2112
/*
@@ -212,12 +212,22 @@ extern "C" {
#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID
#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID
#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID
-#define MDP_PROFILE_ID MDP_SVCLASS_ID
-#define MDP_SOURCE_PROFILE_ID MDP_SROUCE_SVCLASS_ID
-#define MDP_SINK_PROFILE_ID MDP_SINK_SVCLASS_ID
+#define HDP_PROFILE_ID HDP_SVCLASS_ID
+#define HDP_SOURCE_PROFILE_ID HDP_SOURCE_SVCLASS_ID
+#define HDP_SINK_PROFILE_ID HDP_SINK_SVCLASS_ID
#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID
/*
+ * Compatibility macros for the old MDP acronym
+ */
+#define MDP_SVCLASS_ID HDP_SVCLASS_ID
+#define MDP_SOURCE_SVCLASS_ID HDP_SOURCE_SVCLASS_ID
+#define MDP_SINK_SVCLASS_ID HDP_SINK_SVCLASS_ID
+#define MDP_PROFILE_ID HDP_PROFILE_ID
+#define MDP_SOURCE_PROFILE_ID HDP_SOURCE_PROFILE_ID
+#define MDP_SINK_PROFILE_ID HDP_SINK_PROFILE_ID
+
+/*
* Attribute identifier codes
*/
#define SDP_SERVER_RECORD_HANDLE 0x0000
diff --git a/tools/sdptool.c b/tools/sdptool.c
index 7cca3ca..6fb2e90 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -322,9 +322,9 @@ static struct uuid_def uuid16_names[] = {
{ 0x1303, "VideoSource", NULL, 0 },
{ 0x1304, "VideoSink", NULL, 0 },
{ 0x1305, "VideoDistribution", NULL, 0 },
- { 0x1400, "MDP", NULL, 0 },
- { 0x1401, "MDPSource", NULL, 0 },
- { 0x1402, "MDPSink", NULL, 0 },
+ { 0x1400, "HDP", NULL, 0 },
+ { 0x1401, "HDPSource", NULL, 0 },
+ { 0x1402, "HDPSink", NULL, 0 },
{ 0x2112, "AppleAgent", NULL, 0 },
};
--
1.7.0.4
^ permalink raw reply related
* RE: [PATCH 2/3] Replace hci_recv_fragment calls
From: Marcel Holtmann @ 2010-06-01 19:59 UTC (permalink / raw)
To: Luis Rodriguez
Cc: Suraj Sumangala, linux-bluetooth@vger.kernel.org,
Jothikumar Mothilal
In-Reply-To: <BD672EAEE3AD2C47A7120B0973C3FB3A2DC28BB600@SC1EXMB-MBCL.global.atheros.com>
Hi Luis,
> You want to unify patches 1 and 2. Patches upstream should be atomic so that if you apply it, it should make everything still work. Your first patch removes hci_recv_fragment() and then this one fixes the places that call it, you want to do both in one shot.
actually I prefer to leave these two patches out for now. Since the
renaming could be done easily later. The important part is actually the
other implementation.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 2/3] Replace hci_recv_fragment calls
From: Luis R. Rodriguez @ 2010-06-01 20:51 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, Suraj Sumangala, linux-bluetooth@vger.kernel.org,
Jothikumar Mothilal
In-Reply-To: <1275422353.2182.5.camel@localhost.localdomain>
On Tue, Jun 01, 2010 at 12:59:13PM -0700, Marcel Holtmann wrote:
> Hi Luis,
>
> > You want to unify patches 1 and 2. Patches upstream should be atomic so that if you apply it, it should make everything still work. Your first patch removes hci_recv_fragment() and then this one fixes the places that call it, you want to do both in one shot.
>
> actually I prefer to leave these two patches out for now. Since the
> renaming could be done easily later. The important part is actually the
> other implementation.
Won't that break compilation on the first patch since all existing
code users no longer have the exported symbol available?
Luis
^ permalink raw reply
* Re: [PATCH 2/3] Replace hci_recv_fragment calls
From: Marcel Holtmann @ 2010-06-01 21:59 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Luis Rodriguez, Suraj Sumangala, linux-bluetooth@vger.kernel.org,
Jothikumar Mothilal
In-Reply-To: <20100601205120.GB6037@tux>
Hi Luis,
> > > You want to unify patches 1 and 2. Patches upstream should be atomic so that if you apply it, it should make everything still work. Your first patch removes hci_recv_fragment() and then this one fixes the places that call it, you want to do both in one shot.
> >
> > actually I prefer to leave these two patches out for now. Since the
> > renaming could be done easily later. The important part is actually the
> > other implementation.
>
> Won't that break compilation on the first patch since all existing
> code users no longer have the exported symbol available?
no. The important change here is for the H4 specific stream fragment
handling. The rest is just a renaming. So 3/3 is the important patch and
1/2 and 2/2 are just cosmetic changes.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 2/3] Replace hci_recv_fragment calls
From: Suraj Sumangala @ 2010-06-02 4:11 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Luis Rodriguez, Suraj Sumangala, linux-bluetooth@vger.kernel.org,
Jothikumar Mothilal
In-Reply-To: <1275429550.2182.7.camel@localhost.localdomain>
Hi Marcel,
On 6/2/2010 3:29 AM, Marcel Holtmann wrote:
> Hi Luis,
>
>>>> You want to unify patches 1 and 2. Patches upstream should be atomic so that if you apply it, it should make everything still work. Your first patch removes hci_recv_fragment() and then this one fixes the places that call it, you want to do both in one shot.
>>>
>>> actually I prefer to leave these two patches out for now. Since the
>>> renaming could be done easily later. The important part is actually the
>>> other implementation.
>>
>> Won't that break compilation on the first patch since all existing
>> code users no longer have the exported symbol available?
>
> no. The important change here is for the H4 specific stream fragment
> handling. The rest is just a renaming. So 3/3 is the important patch and
> 1/2 and 2/2 are just cosmetic changes.
>
> Regards
>
> Marcel
>
>
I will send 3/3 as a separate patch for you to verify.
Regards
Suraj
^ permalink raw reply
* [PATCH v2] frame reassembly implementation for data stream
From: suraj @ 2010-06-02 8:24 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, Luis.Rodriguez, Jothikumar.Mothilal
Implemented hci_recv_stream_fragment to reassemble HCI packets received from a data stream.
Signed-off-by: suraj <suraj@Atheros.com>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 98 ++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e42f6ed..6f33f11 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -428,6 +428,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 5e83f8e..ac9ccf7 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1033,6 +1033,104 @@ EXPORT_SYMBOL(hci_recv_frame);
/* Receive packet type fragment */
#define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2])
+#define __get_max_rx_size(type) \
+ (((type) == HCI_ACLDATA_PKT) ? \
+ HCI_MAX_FRAME_SIZE : \
+ ((type) == HCI_EVENT_PKT) ? HCI_MAX_EVENT_SIZE :\
+ HCI_MAX_SCO_SIZE)
+
+#define __get_header_len(type) \
+ (((type) == HCI_ACLDATA_PKT) ? \
+ HCI_ACL_HDR_SIZE : \
+ ((type) == HCI_EVENT_PKT) ? HCI_EVENT_HDR_SIZE :\
+ HCI_SCO_HDR_SIZE)
+
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
+{
+ int type;
+
+ while (count) {
+ struct sk_buff *skb = __reassembly(hdev, HCI_ACLDATA_PKT);
+
+ struct { int expect; int pkt_type; } *scb;
+ int len = 0;
+
+ if (!skb) {
+ struct { char type; } *pkt;
+
+ /* Start of the frame */
+ pkt = data;
+ type = pkt->type;
+
+ if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+ return -EILSEQ;
+
+ len = __get_max_rx_size(type);
+
+ skb = bt_skb_alloc(len, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ scb = (void *) skb->cb;
+ scb->expect = __get_header_len(type);
+ scb->pkt_type = type;
+
+ skb->dev = (void *) hdev;
+ __reassembly(hdev, HCI_ACLDATA_PKT) = skb;
+
+ data++;
+ count--;
+
+ continue;
+ } else {
+ scb = (void *) skb->cb;
+ len = min(scb->expect, count);
+ type = scb->pkt_type;
+
+ memcpy(skb_put(skb, len), data, len);
+
+ count -= len;
+ data += len;
+ scb->expect -= len;
+ }
+
+ switch (type) {
+ case HCI_EVENT_PKT:
+ if (skb->len == HCI_EVENT_HDR_SIZE) {
+ struct hci_event_hdr *h = hci_event_hdr(skb);
+ scb->expect = h->plen;
+ }
+ break;
+
+ case HCI_ACLDATA_PKT:
+ if (skb->len == HCI_ACL_HDR_SIZE) {
+ struct hci_acl_hdr *h = hci_acl_hdr(skb);
+ scb->expect = __le16_to_cpu(h->dlen);
+ }
+ break;
+
+ case HCI_SCODATA_PKT:
+ if (skb->len == HCI_SCO_HDR_SIZE) {
+ struct hci_sco_hdr *h = hci_sco_hdr(skb);
+ scb->expect = h->dlen;
+ }
+ break;
+ }
+
+ if (scb->expect == 0) {
+ /* Complete frame */
+
+ __reassembly(hdev, HCI_ACLDATA_PKT) = NULL;
+
+ bt_cb(skb)->pkt_type = type;
+ hci_recv_frame(skb);
+ }
+
+ }
+ return 0;
+}
+EXPORT_SYMBOL(hci_recv_stream_fragment);
+
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
{
if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
--
1.7.0
^ permalink raw reply related
* [PATCH 00/32] Health device profile (HDP)
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:18 UTC (permalink / raw)
To: linux-bluetooth
Next patches are aplied over the MCAP patches sended to thie mailing list by
Santiago Carot. This a first patches manage the creation of links beetween
instances and begins the support for creating data chanels, but doesn't
finish it yet.
Regards
^ permalink raw reply
* [PATCH 01/32] Add Health api description
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-1-git-send-email-santoscadenas@gmail.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 7156 bytes --]
This API describes the interface shown by the Health plugin through d-bus
---
doc/health-api.txt | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 217 insertions(+), 0 deletions(-)
create mode 100644 doc/health-api.txt
diff --git a/doc/health-api.txt b/doc/health-api.txt
new file mode 100644
index 0000000..83e29af
--- /dev/null
+++ b/doc/health-api.txt
@@ -0,0 +1,217 @@
+BlueZ D-Bus Health API description
+**********************************
+
+ Santiago Carot-Nemesio <sancane@gmail.com>
+ José Antonio Santos-Cadenas <santoscadenas@gmail.com>
+ Elvis Pfützenreuter <epx@signove.com>
+
+Health Device Profile hierarchy
+===============================
+
+Service org.bluez
+Interface org.bluez.HealthAdapter
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods:
+
+ uint32 CreateInstance(object path, dict config)
+
+ Returns the id of the new created instance. The path parameter
+ is the path of the remote object with the callbacks to notify
+ events (see org.bluez.HealthAgent at the end of this document)
+ This petition starts an mcap instance and also register in the
+ SDP if is needed.
+
+ Dict is defined as bellow:
+ { "data_spec" : The data_spec is the data exchange specification
+ (see section 5.2.10 of the specification
+ document) possible values:
+ 0x00 = reserved,
+ 0x01 [IEEE 11073-20601],
+ 0x02..0xff reserved,
+ (optional)
+ "end_points" : [{ (optional)
+ "mdepid" : uint8, (optional)
+ "role" : ("source" or "sink"), (mandatory)
+ "specs" :[{ (mandatory)
+ "data_type" : uint16, (mandatory)
+ "description" : string, (optional)
+ }]
+ }]
+ }
+
+ if "data_spec" is not set, no SDP record will be registered, so
+ all the other data in the dictionary will be ignored.
+
+ Instance will be closed by the call or implicitly when the
+ programs leaves the bus.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ void CloseInstance(uint32 )
+
+ Closes the HDP instance identified by the object path. Also
+ instance will be closed if the process that started leaves the
+ bus. If there is a SDP record associated to this instance it
+ will be removed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthDevice
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods:
+
+ array GetHealthInstances()
+
+ Gets the information of the remote instances present in this
+ device and published on its SDP record. The returned data
+ follows this format.
+
+ [{"id": uint32,
+ "data_spec" : data spec,
+ "end_points":
+ ["mdepid": uint8,
+ "role" : "source" or "sink" ,
+ "specs" : [{
+ "dtype" : uint16,
+ "description" : string, (optional)
+ }]
+ ]
+ }];
+
+ object Connect(uint32 local_instance_id, uint32 remote_instance_id)
+
+ Connects the local instance with the remote instance and returns
+ the path of the HealthLink object. You should get the remote
+ instance id running GetHealthInstances.
+
+ Only the bus client that created the local session will be able
+ to create connections using it.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ void Disconnect(object link, boolean cache)
+
+ Disconnect from the link. If cache is false, state will also be
+ deleted. Otherwise, the state will be kept for allowing future
+ reconnections until the adapter holding the local session is
+ removed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthLink
+Object path [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_inst_id
+
+Methods:
+
+ boolean Echo(array{byte})
+
+ Sends an echo petition to the remote intance. Returns True if
+ response matches with the buffer sent. If some error is detected
+ False value is returned and the associated MCL is closed.
+
+ uint16 OpenDataChannel(byte mdepid, byte config)
+
+ Creates a new data channel with the indicated config to the
+ remote MCAP Data End Point (MDEP).
+ The configuration should indicate the channel quality of
+ service. In the current version of HDP, valid values are 0x01
+ for reliable channels and 0x02 for streaming data channel.
+
+ Returns the data channel id.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ array GetDataChannelFileDescriptor(uint16 mdlid)
+
+ Gets a file descriptor where data can be read or
+ written for receive or sent by the data channel.
+ Returns an array of file descriptors one for write
+ and other for read.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+ void DeleteDataChannel(uint16 mdlid)
+
+ Deletes a data channel so it will not be available for
+ use.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+ void DeleteAllDataChannels()
+
+ Deletes all data channels so it will not be available
+ for use. Typically this function is called when the
+ connection with the remote device will be closed
+ permanently
+
+ Possible errors: org.bluez.Error.HealthError
+
+ dict GetDataChannelStatus()
+
+ Return a dictionary with all the data channels that
+ can be used to send data right now. The dictionary
+ is formed like follows:
+ {
+ "reliable": [mdlid_r1, mdlid_r2, ...],
+ "streaming" : [mdlid_s1, mdlid_s2, ...]
+ }
+
+ The fist reliable data channel will always be the first
+ data channel in reliable array.
+
+HealthAgent hierarchy
+=====================
+
+(this object is implemented by the HDP user in order to receive notifications)
+
+Service unique name
+Interface org.bluez.HealthAgent
+Object path freely definable
+
+Methods:
+
+ void LinkConnected(object path)
+
+ This method is called whenever a new connection has been
+ established over the control channel of the current HDP
+ instance. The object path paremeter contains the object path of
+ the created HealthLink.
+
+ void LinkDisconnected(object path)
+
+ This method is called when a remote device is disconnected
+ definitively. Any future reconnections will fail. Also all data
+ channels associated to this device will be closed.
+
+ void CreatedDataChannel(object path, uint16 mdlid, byte conf)
+
+ This method is called when a new data channel is created
+
+ The path contains the object path of the HealthLink where the
+ new connection is created, the mdlid is the data channel
+ identificator and conf is the que quality of service of the data
+ channel (0x01 reliable, 0x02 streaming).
+
+ void DeletedDataChannel(object path, uint16 mdlid)
+
+ This method is called when a data channel is closed.
+
+ After this call the data channel id will not be valid and can be
+ reused for future created data channels.
--
1.6.3.3
^ permalink raw reply related
* [PATCH 02/32] Initial support for HDP
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-2-git-send-email-santoscadenas@gmail.com>
Creates the basic structure of the plugin, registering
adapter and device drivers.
---
Makefile.am | 8 +
acinclude.m4 | 8 +-
health/hdp.c | 183 +++++++++++++++++++++
health/hdp.h | 27 +++
health/hdp_types.h | 99 ++++++++++++
health/hdp_util.c | 447 ++++++++++++++++++++++++++++++++++++++++++++++++++++
health/hdp_util.h | 34 ++++
health/main.c | 60 +++++++
health/manager.c | 101 ++++++++++++
health/manager.h | 27 +++
10 files changed, 993 insertions(+), 1 deletions(-)
create mode 100644 health/hdp.c
create mode 100644 health/hdp.h
create mode 100644 health/hdp_types.h
create mode 100644 health/hdp_util.c
create mode 100644 health/hdp_util.h
create mode 100644 health/main.c
create mode 100644 health/manager.c
create mode 100644 health/manager.h
diff --git a/Makefile.am b/Makefile.am
index 9ab5be2..d30850f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -169,6 +169,14 @@ builtin_modules += service
builtin_sources += plugins/service.c
endif
+if HEALTHPLUGIN
+builtin_modules += health
+builtin_sources += health/main.c \
+ health/manager.h health/manager.c \
+ health/hdp.h health/hdp.c \
+ health/hdp_util.h health/hdp_util.c
+endif
+
if MCAP
mcap_sources += mcap/mcap_internal.h \
mcap/mcap_lib.h mcap/sync.c \
diff --git a/acinclude.m4 b/acinclude.m4
index b512cfb..23c594a 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -167,6 +167,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
serial_enable=yes
network_enable=yes
service_enable=yes
+ health_enable=no
mcap_enable=no
pnat_enable=no
tracer_enable=no
@@ -216,6 +217,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
service_enable=${enableval}
])
+ AC_ARG_ENABLE(health, AC_HELP_STRING([--enable-health], [enable health plugin]), [
+ health_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(mcap, AC_HELP_STRING([--enable-mcap], [enable mcap support]), [
mcap_enable=${enableval}
])
@@ -330,7 +335,8 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
- AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes")
+ AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
+ AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes" || test "${health_enable}" = "yes")
AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
diff --git a/health/hdp.c b/health/hdp.c
new file mode 100644
index 0000000..281be05
--- /dev/null
+++ b/health/hdp.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <gdbus.h>
+
+#include "logging.h"
+#include "error.h"
+
+#include "hdp_types.h"
+#include "hdp_util.h"
+
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+
+#include "../src/dbus-common.h"
+
+static GSList *adapters = NULL;
+
+static struct hdp_adapter *find_adapter(GSList *list,
+ struct btd_adapter *btd_adapter)
+{
+ GSList *l;
+ struct hdp_adapter *adapter;
+
+ for (l = list; l; l = l->next) {
+ adapter = l->data;
+ if (adapter->btd_adapter == btd_adapter)
+ return adapter;
+ }
+
+ return NULL;
+}
+
+static void hdp_set_instance_id(struct hdp_instance *hdpi)
+{
+ struct hdp_adapter *adapter = hdpi->adapter;
+
+ hdpi->id = adapter->ic++;
+}
+
+static DBusMessage *hdp_create_instance(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_adapter *adapter = user_data;
+ const char *path, *name;
+ DBusMessageIter iter;
+ GError *err = NULL;
+ DBusMessage *reply;
+ struct hdp_instance *hdpi;
+ struct hdp_config *config;
+ int ctype;
+
+ dbus_message_iter_init(msg, &iter);
+ ctype = dbus_message_iter_get_arg_type(&iter);
+ if (ctype != DBUS_TYPE_OBJECT_PATH)
+ goto error;
+ dbus_message_iter_get_basic(&iter, &path);
+ dbus_message_iter_next(&iter);
+ config = hdp_get_config(&iter, &err);
+ if (err)
+ goto error;
+ name = dbus_message_get_sender(msg);
+ if (!name) {
+ g_set_error(&err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Can't get sender name");
+ goto error;
+ }
+
+ hdpi = g_new0(struct hdp_instance, 1);
+ hdpi->adapter = adapter;
+ hdpi->aname = g_strdup(name);
+ hdpi->apath = g_strdup(path);
+ hdpi->config = config;
+ if (!config->svc_dsc)
+ config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
+ if (!config->svc_name)
+ config->svc_name = g_strdup(HDP_SERVICE_NAME);
+ if (!config->svc_prov)
+ config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
+ hdp_set_instance_id(hdpi);
+
+ /* TODO: Create mcap instance */
+
+ /* TODO: Create SDP record if needed. */
+
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".HealthError",
+ "Incomplete call yet");
+error:
+ if (err) {
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments: %s", err->message);
+ g_error_free(err);
+ } else
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return reply;
+}
+
+static GDBusMethodTable hdp_methods[] = {
+ { "CreateInstance", "oa{sv}", "u", hdp_create_instance },
+ { NULL }
+};
+
+void hdp_delete_instance_iter(gpointer data, gpointer user_data)
+{
+ /* struct hdp_instance *hdpi = data; */
+
+ /* TODO: Create a free function */
+}
+
+static void hdp_path_unregister(void *data)
+{
+ struct hdp_adapter *adapter = data;
+
+ g_slist_foreach(adapter->instances, hdp_delete_instance_iter, NULL);
+ g_slist_free(adapter->instances);
+ adapter->instances = NULL;
+ debug("All hdp instance for removed adapter were closed");
+}
+
+int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
+{
+ const char *path = adapter_get_path(btd_adapter);
+
+ struct hdp_adapter *adapter;
+ adapter = g_new0(struct hdp_adapter, 1);
+
+ debug("HDP init");
+ if (!g_dbus_register_interface(conn, path, HEALTH_MANAGER_INTERFACE,
+ hdp_methods, NULL, NULL,
+ adapter, hdp_path_unregister)) {
+ error("Failed to register %s interface to %s",
+ HEALTH_MANAGER_INTERFACE, path);
+ g_free(adapter);
+ return -1;
+ }
+ adapter->conn = dbus_connection_ref(conn);
+ adapter->btd_adapter = btd_adapter_ref(btd_adapter);
+ adapters = g_slist_prepend(adapters, adapter);
+ return 0;
+}
+
+void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
+{
+ struct hdp_adapter *adapter;
+
+ adapter = find_adapter(adapters, btd_adapter);
+ if (!adapter)
+ return;
+
+ g_dbus_unregister_interface(adapter->conn,
+ adapter_get_path(btd_adapter),
+ HEALTH_MANAGER_INTERFACE);
+ dbus_connection_unref(adapter->conn);
+ btd_adapter_unref(adapter->btd_adapter);
+ adapters = g_slist_remove(adapters, adapter);
+ g_free(adapter);
+
+ debug("HDP exit");
+}
diff --git a/health/hdp.h b/health/hdp.h
new file mode 100644
index 0000000..893f745
--- /dev/null
+++ b/health/hdp.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
+void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
diff --git a/health/hdp_types.h b/health/hdp_types.h
new file mode 100644
index 0000000..2db9adf
--- /dev/null
+++ b/health/hdp_types.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+
+#ifndef __HDP_TYPES_H__
+#define __HDP_TYPES_H__
+
+#include <glib.h>
+#include "mcap_lib.h"
+
+#define HDP_SERVICE_NAME "Bluez HDP"
+#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
+#define HDP_SERVICE_PROVIDER "Bluez"
+
+#define HDP_VERSION 0x0100
+
+#define HDP_ERROR g_quark_from_static_string("hdp-error-quark")
+
+typedef enum {
+ HDP_DIC_PARSE_ERROR,
+ HDP_DIC_ENTRY_PARSE_ERROR,
+ HDP_UNSPECIFIED_ERROR,
+ HDP_UNKNOWN_ERROR
+} HdpError;
+
+enum data_specs {
+ DATA_EXCHANGE_SPEC_11073 = 0x01
+};
+
+typedef enum {
+ HDP_SOURCE = 0x00,
+ HDP_SINK = 0x01
+} HdpRole;
+
+struct hdp_feature {
+ guint16 dtype; /* Data type (see 5.2.9.2) */
+ gboolean dtype_present; /* Data type present in config */
+ char *dscr; /* Displayable TextName */
+};
+
+struct hdp_supp_fts {
+ guint8 mdepid; /* (0x01-0x7F) Available for use */
+ HdpRole role; /* Role (see table 5.3) */
+ gboolean role_present; /* Role present in config */
+ GSList *features; /* Feature list */
+};
+
+struct hdp_config {
+ guint8 data_spec; /* Data exchange specification */
+ GSList *supp_fts; /* Supported features list */
+ char *svc_name; /* Service name to register in SDP */
+ char *svc_dsc; /* Service description */
+ char *svc_prov; /* Service provider */
+ gboolean ds_present; /* Data spec has been assigned */
+};
+
+struct hdp_adapter {
+ struct btd_adapter *btd_adapter;
+ DBusConnection *conn; /* DBus connection */
+ GSList *instances; /* HDP instances list */
+ uint16_t ic; /* Instances counter */
+};
+
+struct hdp_instance {
+ struct hdp_adapter *adapter; /* HDP adapter */
+ struct mcap_instance *mi; /* MCAP instance */
+ uint16_t ccpsm; /* Control channel psm */
+ uint16_t dcpsm; /* Data channel psm */
+ GSList *hlink; /* Health Links */
+ uint32_t id; /* HDP instance id */
+ char *apath; /* HDP agent path */
+ char *aname; /* HDP agent name */
+ struct hdp_config *config; /* Configuration */
+ uint32_t sdp_handler; /* SDP record handler */
+};
+
+#endif /* __HDP_TYPES_H__ */
diff --git a/health/hdp_util.c b/health/hdp_util.c
new file mode 100644
index 0000000..8f6befc
--- /dev/null
+++ b/health/hdp_util.c
@@ -0,0 +1,447 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gdbus.h>
+#include "logging.h"
+#include "hdp_types.h"
+
+typedef gboolean (*parse_item_f)(DBusMessageIter *iter, GError **err,
+ gpointer user_data);
+
+struct dict_entry_func {
+ char *key;
+ parse_item_f func;
+};
+
+static gboolean check_feature(struct hdp_feature *feature)
+{
+ return feature->dtype_present;
+}
+
+static gboolean check_feature_list(struct hdp_supp_fts *fts)
+{
+ return fts->role_present && (fts->features != NULL);
+}
+
+static gboolean check_config(struct hdp_config *config)
+{
+ if (config->ds_present)
+ return config->supp_fts != NULL;
+ return TRUE;
+}
+
+static gboolean hdp_check_data_spec(guint8 data_spec)
+{
+ /* Future versions may edit this function
+ * If there are more supported data exchange specifications
+ */
+ return data_spec == DATA_EXCHANGE_SPEC_11073;
+}
+
+static void free_feature(struct hdp_feature *feature)
+{
+ if (feature->dscr) {
+ g_free(feature->dscr);
+ feature->dscr = NULL;
+ }
+ g_free(feature);
+}
+
+static void free_feature_list(struct hdp_supp_fts *fts)
+{
+ GSList *l;
+
+ for (l = fts->features; l; l = l->next)
+ free_feature(l->data);
+ g_slist_free(fts->features);
+ fts->features = NULL;
+ g_free(fts);
+}
+
+static void free_config(struct hdp_config *config)
+{
+ GSList *l;
+
+ for (l = config->supp_fts; l; l = l->next)
+ free_feature_list(l->data);
+ g_slist_free(config->supp_fts);
+ config->supp_fts = NULL;
+ if (config->svc_dsc) {
+ g_free(config->svc_dsc);
+ config->svc_dsc = NULL;
+ }
+ if (config->svc_name) {
+ g_free(config->svc_name);
+ config->svc_name = NULL;
+ }
+ if (config->svc_prov) {
+ g_free(config->svc_prov);
+ config->svc_prov = NULL;
+ }
+ g_free(config);
+}
+
+static gboolean parse_dict_entry(struct dict_entry_func dict_context[],
+ DBusMessageIter *iter,
+ GError **err,
+ gpointer user_data)
+{
+ DBusMessageIter entry;
+ char *key;
+ int ctype, i;
+ struct dict_entry_func df;
+
+ dbus_message_iter_recurse(iter, &entry);
+ ctype = dbus_message_iter_get_arg_type(&entry);
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Dictionary entries should have a string as key");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ /* Find function and call it */
+ for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) {
+ if (g_strcmp0(df.key, key) == 0) {
+ return df.func(&entry, err, user_data);
+ }
+ }
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "No function found for parsing value for key %s", key);
+ return FALSE;
+}
+
+static gboolean parse_dict(struct dict_entry_func dict_context[],
+ DBusMessageIter *iter,
+ GError **err,
+ gpointer user_data)
+{
+ int ctype;
+ DBusMessageIter dict;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary should be an array");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID) {
+ if (ctype != DBUS_TYPE_DICT_ENTRY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary array should "
+ "contain dict entries");
+ return FALSE;
+ }
+ /* Start parsing entry */
+ if (!parse_dict_entry(dict_context, &dict, err,
+ user_data))
+ return FALSE;
+ /* Finish entry parsing */
+ dbus_message_iter_next(&dict);
+ }
+ return TRUE;
+}
+
+static gboolean parse_description(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_feature *feat = data;
+ DBusMessageIter *string, variant;
+ int ctype;
+ const char *desc;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ string = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &variant);
+ ctype = dbus_message_iter_get_arg_type(&variant);
+ string = &variant;
+ }
+
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Value data spec should be variable or string");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(string, &desc);
+ feat->dscr = g_strdup(desc);
+ return TRUE;
+}
+
+static gboolean parse_data_type(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_feature *feat = data;
+ DBusMessageIter *value, variant;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ value = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &variant);
+ ctype = dbus_message_iter_get_arg_type(&variant);
+ value = &variant;
+ }
+
+ if (ctype != DBUS_TYPE_UINT16) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Final value for data type should be a uint16");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(value, &feat->dtype);
+
+ /*
+ * This data should be check by the application layer because it
+ * depends on the data_spec values and is specific for each value
+ */
+ feat->dtype_present = TRUE;
+
+ return TRUE;
+}
+
+static struct dict_entry_func specs_context[] = {
+ {"data_type", parse_data_type},
+ {"description", parse_description},
+ {NULL, NULL}
+};
+
+static gboolean parse_specs(DBusMessageIter *iter, GError **err, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ struct hdp_feature *feature = NULL;
+ DBusMessageIter *array, value, dict;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ array = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ array = &value;
+ }
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Value specs should be variable or array");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(array, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID){
+ feature = g_new0(struct hdp_feature, 1);
+ if (!parse_dict(specs_context, &dict, err, feature))
+ goto error;
+ if (!check_feature(feature)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Field \"data_type\" is mandatory");
+ goto error;
+ }
+ fts->features = g_slist_append(fts->features, feature);
+ dbus_message_iter_next(&dict);
+ }
+
+ return TRUE;
+error:
+ if (feature)
+ free_feature(feature);
+ return FALSE;
+}
+
+static gboolean parse_role(DBusMessageIter *iter, GError **err, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ DBusMessageIter value;
+ DBusMessageIter *string;
+ int ctype;
+ const char *role;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ string = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ string = &value;
+ }
+
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value data spec should be variable or string");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(string, &role);
+ if (g_strcmp0(role, "sink") == 0)
+ fts->role = HDP_SINK;
+ else if (g_strcmp0(role, "source") == 0)
+ fts->role = HDP_SOURCE;
+ else {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Role value should be \"source\" or \"sink\"");
+ return FALSE;
+ }
+ fts->role_present = TRUE;
+ return TRUE;
+}
+
+static struct dict_entry_func end_point_context[] = {
+ {"role", parse_role},
+ {"specs", parse_specs},
+ {NULL, NULL}
+};
+
+static gboolean parse_end_points(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_config *config = data;
+ struct hdp_supp_fts *fts = NULL;
+ DBusMessageIter array, dict;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_VARIANT) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value for end points should be variable");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &array);
+ ctype = dbus_message_iter_get_arg_type(&array);
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value end_point should be array inside variable");
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse(&array, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID){
+
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary should be an array");
+ return FALSE;
+ }
+ fts = g_new0(struct hdp_supp_fts, 1);
+ if (!parse_dict(end_point_context, &dict, err, fts))
+ goto error;
+ if (!check_feature_list(fts)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Role field and specs are mandatory");
+ goto error;
+ }
+ config->supp_fts = g_slist_append(config->supp_fts, fts);
+ dbus_message_iter_next(&dict);
+ }
+ return TRUE;
+error:
+ if (fts)
+ free_feature_list(fts);
+ return FALSE;
+}
+
+static gboolean parse_data_spec(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_config *config = data;
+ DBusMessageIter value;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_VARIANT) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value data spec should be variable");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ if (ctype != DBUS_TYPE_BYTE) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Final value data spec should be byte");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(&value, &config->data_spec);
+
+ if (!hdp_check_data_spec(config->data_spec))
+ return FALSE;
+ config->ds_present = TRUE;
+ return TRUE;
+}
+
+static struct dict_entry_func main_context[] = {
+ {"data_spec", parse_data_spec},
+ {"end_points", parse_end_points},
+ {NULL, NULL}
+};
+
+static void print_feature(gpointer elem, gpointer data)
+{
+ struct hdp_feature *feat = elem;
+
+ debug(" Feature:");
+ debug(" description: %s", feat->dscr);
+ debug(" data type: %u", feat->dtype);
+}
+
+static void print_features(gpointer elem, gpointer data)
+{
+ struct hdp_supp_fts *fts = elem;
+
+ debug("Mdep:");
+ debug(" mdepid %u", fts->mdepid);
+ debug(" role %d", fts->role);
+ g_slist_foreach(fts->features, print_feature, NULL);
+}
+
+struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err)
+{
+ struct hdp_config *config;
+
+ config = g_new0(struct hdp_config, 1);
+
+ if (!parse_dict(main_context, iter, err, config))
+ goto error;
+
+ /* TODO check config */
+ if (!check_config(config)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "\"data_spec\" and \"end_point\" should be set or not");
+ goto error;
+ }
+ if (!config->ds_present)
+ goto error;
+ debug("config->data_spec %d", config->data_spec);
+ g_slist_foreach(config->supp_fts, print_features, NULL);
+ return config;
+error:
+ if (config)
+ free_config(config);
+ return NULL;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
new file mode 100644
index 0000000..f09e9a6
--- /dev/null
+++ b/health/hdp_util.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __HDP_UTIL_H__
+#define __HDP_UTIL_H__
+
+#include <gdbus.h>
+#include "hdp_types.h"
+
+struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
+
+#endif /* __HDP_UTIL_H__ */
diff --git a/health/main.c b/health/main.c
new file mode 100644
index 0000000..6ece69b
--- /dev/null
+++ b/health/main.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int hdp_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (hdp_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void hdp_exit(void)
+{
+ hdp_manager_exit();
+
+ dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(health, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, hdp_init, hdp_exit)
diff --git a/health/manager.c b/health/manager.c
new file mode 100644
index 0000000..b5dec5a
--- /dev/null
+++ b/health/manager.c
@@ -0,0 +1,101 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "device.h"
+
+#include "logging.h"
+#include "manager.h"
+#include "hdp.h"
+
+#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
+#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
+#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+
+static DBusConnection *connection = NULL;
+
+static int hdp_adapter_probe(struct btd_adapter *adapter)
+{
+ return hdp_adapter_register(connection, adapter);
+}
+
+static void hdp_adapter_remove(struct btd_adapter *adapter)
+{
+ hdp_adapter_unregister(adapter);
+}
+
+static struct btd_adapter_driver hdp_adapter_driver = {
+ .name = "hdp-adapter-driver",
+ .probe = hdp_adapter_probe,
+ .remove = hdp_adapter_remove,
+};
+
+static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ debug("hdp driver probe");
+ return 0;
+}
+
+static void hdp_driver_remove(struct btd_device *device)
+{
+ debug("hdp driver remove");
+}
+
+static struct btd_device_driver hdp_device_driver = {
+ .name = "hdp_device-driver",
+ .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
+ .probe = hdp_driver_probe,
+ .remove = hdp_driver_remove,
+};
+
+int hdp_manager_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+
+ btd_register_adapter_driver(&hdp_adapter_driver);
+ btd_register_device_driver(&hdp_device_driver);
+
+ debug("hdp manager init");
+ return 0;
+}
+
+void hdp_manager_exit(void)
+{
+ btd_unregister_device_driver(&hdp_device_driver);
+ btd_unregister_adapter_driver(&hdp_adapter_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+ debug("hdp manager exit");
+}
diff --git a/health/manager.h b/health/manager.h
new file mode 100644
index 0000000..b91ef75
--- /dev/null
+++ b/health/manager.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int hdp_manager_init(DBusConnection *conn);
+void hdp_manager_exit(void);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 03/32] Add functions to resiger health instances in SDP
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-3-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 5 +-
health/hdp_util.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++++
health/hdp_util.h | 1 +
3 files changed, 398 insertions(+), 1 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 281be05..ede4186 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -101,7 +101,10 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
/* TODO: Create mcap instance */
- /* TODO: Create SDP record if needed. */
+ if (!hdp_register_sdp_record(hdpi)) {
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Session can't be registered");
+ }
return g_dbus_create_error(msg,
ERROR_INTERFACE ".HealthError",
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 8f6befc..b386be5 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -24,8 +24,14 @@
*/
#include <gdbus.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include "logging.h"
+#include "sdpd.h"
+
#include "hdp_types.h"
+#include "hdp_util.h"
+#include "mcap.h"
typedef gboolean (*parse_item_f)(DBusMessageIter *iter, GError **err,
gpointer user_data);
@@ -445,3 +451,390 @@ error:
free_config(config);
return NULL;
}
+
+static gboolean is_session_role(struct hdp_instance *hdps, HdpRole role)
+{
+ GSList *l;
+ struct hdp_supp_fts *fts;
+
+ if (!hdps->config)
+ return FALSE;
+ for (l = hdps->config->supp_fts; l; l = l->next) {
+ fts = l->data;
+ if (fts->role == role)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean register_service_protocols(struct hdp_instance *hdps,
+ sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ uuid_t l2cap_uuid, mcap_c_uuid;
+ sdp_list_t *l2cap_list = NULL,
+ *proto_list = NULL,
+ *mcap_list = NULL,
+ *access_proto_list = NULL;
+ sdp_data_t *psm = NULL,
+ *mcap_ver = NULL;
+ uint16_t version = MCAP_VERSION;
+
+ // set l2cap information
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list) {
+ error = TRUE;
+ goto end;
+ }
+ psm = sdp_data_alloc(SDP_UINT16, &hdps->ccpsm);
+ if (!psm) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append(l2cap_list, psm)) {
+ error = TRUE;
+ goto end;
+ }
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list) {
+ error = TRUE;
+ goto end;
+ }
+
+ // set mcap information
+ sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_c_uuid);
+ if (!mcap_list) {
+ error = TRUE;
+ goto end;
+ }
+ mcap_ver = sdp_data_alloc(SDP_UINT16, &version);
+ if (!mcap_ver) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( mcap_list, mcap_ver)) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( proto_list, mcap_list)) {
+ error = TRUE;
+ goto end;
+ }
+
+ // attach protocol information to service record
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (sdp_set_access_protos(sdp_record, access_proto_list) < 0)
+ error = TRUE;
+end:
+ if (l2cap_list)
+ sdp_list_free(l2cap_list, NULL);
+ if (mcap_list)
+ sdp_list_free(mcap_list, NULL);
+ if (proto_list)
+ sdp_list_free(proto_list, NULL);
+ if (access_proto_list)
+ sdp_list_free(access_proto_list, NULL);
+ if (psm)
+ sdp_data_free(psm);
+ if (mcap_ver)
+ sdp_data_free(mcap_ver);
+ return !error;
+}
+
+static gboolean register_service_profiles(sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ sdp_list_t *profile_list = NULL;
+ sdp_profile_desc_t hdp_profile;
+
+ // set hdp information
+ sdp_uuid16_create( &hdp_profile.uuid, MDP_SVCLASS_ID);
+ hdp_profile.version = HDP_VERSION;
+ profile_list = sdp_list_append(NULL, &hdp_profile);
+ if (!profile_list)
+ return FALSE;
+ // set profile descriptor list
+ if (sdp_set_profile_descs(sdp_record, profile_list) < 0)
+ error = TRUE;
+
+ sdp_list_free(profile_list, NULL);
+ return !error;
+}
+
+static gboolean register_service_aditional_protocols(struct hdp_instance *hdps,
+ sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ uuid_t l2cap_uuid, mcap_d_uuid;
+ sdp_list_t *l2cap_list = NULL,
+ *proto_list = NULL,
+ *mcap_list = NULL,
+ *access_proto_list = NULL;
+ sdp_data_t *psm = NULL;
+
+ // set l2cap information
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list) {
+ error = TRUE;
+ goto end;
+ }
+ psm = sdp_data_alloc(SDP_UINT16, &hdps->dcpsm);
+ if (!psm) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append(l2cap_list, psm)) {
+ error = TRUE;
+ goto end;
+ }
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list) {
+ error = TRUE;
+ goto end;
+ }
+
+ // set mcap information
+ sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_d_uuid);
+ if (!mcap_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( proto_list, mcap_list)) {
+ error = TRUE;
+ goto end;
+ }
+
+ // attach protocol information to service record
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0)
+ error = TRUE;
+end:
+ if (l2cap_list)
+ sdp_list_free(l2cap_list, NULL);
+ if (mcap_list)
+ sdp_list_free(mcap_list, NULL);
+ if (proto_list)
+ sdp_list_free(proto_list, NULL);
+ if (access_proto_list)
+ sdp_list_free(access_proto_list, NULL);
+ if (psm)
+ sdp_data_free(psm);
+ return !error;
+}
+
+static sdp_list_t *feature_to_sdplist(struct hdp_supp_fts *fts,
+ struct hdp_feature *f)
+{
+ sdp_data_t *mdepid,
+ *dtype = NULL,
+ *role = NULL,
+ *desc = NULL;
+ sdp_list_t *f_list = NULL;
+
+ mdepid = sdp_data_alloc(SDP_UINT8, &fts->mdepid);
+ if (!mdepid)
+ return NULL;
+ dtype = sdp_data_alloc(SDP_UINT16, &f->dtype);
+ if (!dtype)
+ goto error;
+ role = sdp_data_alloc(SDP_UINT8, &fts->role);
+ if (!role)
+ goto error;
+ if (f->dscr) {
+ desc = sdp_data_alloc(SDP_TEXT_STR8, f->dscr);
+ if (!desc)
+ goto error;
+ }
+ f_list = sdp_list_append(NULL, mdepid);
+ if (!f_list)
+ goto error;
+ if (!sdp_list_append(f_list, dtype))
+ goto error;
+ if (!sdp_list_append(f_list, role))
+ goto error;
+ if (desc)
+ if (!sdp_list_append(f_list, desc))
+ goto error;
+ return f_list;
+error:
+ if (f_list)
+ sdp_list_free(f_list, NULL);
+ if (mdepid)
+ sdp_data_free(mdepid);
+ if (dtype)
+ sdp_data_free(dtype);
+ if (role)
+ sdp_data_free(role);
+ if (desc)
+ sdp_data_free(desc);
+ return NULL;
+}
+
+static gboolean register_features(struct hdp_supp_fts *fts,
+ sdp_list_t **sup_features)
+{
+ GSList *l;
+ sdp_list_t *hdp_feature = NULL;
+
+ for (l = fts->features; l; l = l->next){
+ hdp_feature = feature_to_sdplist(fts, l->data);
+ if (!hdp_feature)
+ goto error;
+
+ if (!*sup_features) {
+ *sup_features = sdp_list_append(NULL, hdp_feature);
+ if (!*sup_features)
+ goto error;
+ } else if (!sdp_list_append(*sup_features, hdp_feature))
+ goto error;
+ hdp_feature = NULL;
+ }
+ return TRUE;
+error:
+ if (hdp_feature)
+ sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free);
+ return FALSE;
+}
+
+static void free_hdp_list(void *list)
+{
+ sdp_list_t *hdp_list = list;
+
+ sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free);
+}
+
+static gboolean register_service_sup_features(struct hdp_config *config,
+ sdp_record_t *sdp_record)
+{
+ GSList *l;
+ sdp_list_t *sup_features = NULL;
+ for (l = config->supp_fts; l; l = l->next) {
+ if (!register_features(l->data, &sup_features))
+ return FALSE;
+ }
+ if (sdp_set_supp_feat(sdp_record, sup_features) < 0) {
+ sdp_list_free(sup_features, free_hdp_list);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean register_data_exchange_spec(struct hdp_config *config,
+ sdp_record_t *record)
+{
+ sdp_data_t *spec;
+
+ spec = sdp_data_alloc(SDP_UINT8, &config->data_spec);
+ if (!spec)
+ return FALSE;
+ if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) {
+ sdp_data_free(spec);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean register_mcap_features(sdp_record_t *sdp_record)
+{
+ sdp_data_t *mcap_proc;
+ uint8_t mcap_sup_proc = MCAP_SUP_PROC;
+
+ mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc);
+ if (!mcap_proc)
+ return FALSE;
+ if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES,
+ mcap_proc) < 0) {
+ sdp_data_free(mcap_proc);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role)
+{
+ uuid_t svc_uuid_source, svc_uuid_sink;
+ sdp_list_t *svc_list = NULL;
+
+ sdp_uuid16_create(&svc_uuid_sink, MDP_SINK_SVCLASS_ID);
+ sdp_uuid16_create(&svc_uuid_source, MDP_SOURCE_SVCLASS_ID);
+
+ sdp_get_service_classes(record, &svc_list);
+
+ if (role == HDP_SOURCE) {
+ if (sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp) == NULL)
+ svc_list = sdp_list_append(svc_list, &svc_uuid_source);
+ }
+ else if (role == HDP_SINK) {
+ if (sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp) == NULL)
+ svc_list = sdp_list_append(svc_list, &svc_uuid_sink);
+ }
+
+ if (sdp_set_service_classes(record, svc_list) < 0) {
+ sdp_list_free(svc_list, NULL);
+ return FALSE;
+ }
+
+ sdp_list_free(svc_list, NULL);
+ return TRUE;
+}
+
+gboolean hdp_register_sdp_record(struct hdp_instance *hdps)
+{
+ sdp_record_t *sdp_record;
+ struct hdp_config *config;
+ bdaddr_t addr;
+
+ if (!hdps->config) /* Record is not needed */
+ return TRUE;
+ config = hdps->config;
+
+ sdp_record = sdp_record_alloc();
+ if (!sdp_record)
+ return FALSE;
+ sdp_record->handle = 0xffffffff; /* Set automatically */
+
+ if (is_session_role(hdps, HDP_SINK))
+ set_sdp_services_uuid(sdp_record, HDP_SINK);
+ if (is_session_role(hdps, HDP_SOURCE))
+ set_sdp_services_uuid(sdp_record, HDP_SOURCE);
+
+ if (!register_service_protocols(hdps, sdp_record))
+ goto error;
+ if (!register_service_profiles(sdp_record))
+ goto error;
+ if (!register_service_aditional_protocols(hdps, sdp_record))
+ goto error;
+ sdp_set_info_attr(sdp_record, config->svc_name, config->svc_prov,
+ config->svc_dsc);
+ if (!register_service_sup_features(config, sdp_record))
+ goto error;
+ if (!register_data_exchange_spec(config, sdp_record))
+ goto error;
+
+ register_mcap_features(sdp_record);
+
+ adapter_get_address(hdps->adapter->btd_adapter, &addr);
+
+ if (add_record_to_server(&addr, sdp_record) < 0)
+ goto error;
+ hdps->sdp_handler = sdp_record->handle;
+ return TRUE;
+error:
+ if (sdp_record)
+ sdp_record_free(sdp_record);
+ return FALSE;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index f09e9a6..fb114c7 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -30,5 +30,6 @@
#include "hdp_types.h"
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
+gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 04/32] Initial support for hdp_device_drivers
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: José Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-4-git-send-email-santoscadenas@gmail.com>
From: José Antonio Santos Cadenas <santoscadenas@gmail.com>
---
health/hdp.c | 11 +++++++++++
health/hdp.h | 3 +++
health/manager.c | 10 +++++++---
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index ede4186..1094170 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -184,3 +184,14 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
debug("HDP exit");
}
+
+int health_device_register(struct btd_device *device, const char *uuid)
+{
+ debug("HDP_DRIVER_PROBE with uuid %s", uuid);
+ return 0;
+}
+
+void health_device_unregister(struct btd_device *device)
+{
+ debug("TODO: Remove device");
+}
diff --git a/health/hdp.h b/health/hdp.h
index 893f745..0aae7b9 100644
--- a/health/hdp.h
+++ b/health/hdp.h
@@ -25,3 +25,6 @@
int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
+
+int health_device_register(struct btd_device *device, const char *uuid);
+void health_device_unregister(struct btd_device *device);
diff --git a/health/manager.c b/health/manager.c
index b5dec5a..9b3b1a5 100644
--- a/health/manager.c
+++ b/health/manager.c
@@ -63,17 +63,21 @@ static struct btd_adapter_driver hdp_adapter_driver = {
static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
{
- debug("hdp driver probe");
+ while (uuids) {
+ health_device_register(device, uuids->data);
+ uuids = uuids->next;
+ }
+
return 0;
}
static void hdp_driver_remove(struct btd_device *device)
{
- debug("hdp driver remove");
+ health_device_unregister(device);
}
static struct btd_device_driver hdp_device_driver = {
- .name = "hdp_device-driver",
+ .name = "hdp-device-driver",
.uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
.probe = hdp_driver_probe,
.remove = hdp_driver_remove,
--
1.6.3.3
^ permalink raw reply related
* [PATCH 05/32] Register healt_driver interfaces in d-bus
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: José Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-5-git-send-email-santoscadenas@gmail.com>
From: José Antonio Santos Cadenas <santoscadenas@gmail.com>
Register interface for each hdp_driver plugged
Unregister driver
Device_get_health_instances method added
Add function to get data exchange spec from a remote record
---
health/hdp.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++---
health/hdp.h | 4 +-
health/hdp_types.h | 10 ++++
health/hdp_util.c | 11 +++++
health/hdp_util.h | 2 +
health/manager.c | 20 +++-----
6 files changed, 151 insertions(+), 22 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 1094170..ae6add4 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -29,12 +29,16 @@
#include "hdp_types.h"
#include "hdp_util.h"
-
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#include "device.h"
#include "../src/dbus-common.h"
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#define HEALTH_INSTANCE_INTERFACE "org.bluez.HealthInstance"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+
static GSList *adapters = NULL;
+static GSList *devices = NULL;
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
@@ -51,6 +55,98 @@ static struct hdp_adapter *find_adapter(GSList *list,
return NULL;
}
+static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
+{
+ GSList *l;
+ struct hdp_device *device;
+
+ for (l = devices; l != NULL; l = l->next) {
+ device = l->data;
+
+ if (device->dev == dev)
+ return device;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *get_health_instances(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ const sdp_record_t *rec;
+ guint8 data_spec;
+
+ rec = btd_device_get_record(device->dev, HDP_UUID);
+
+ if (!rec) {
+ debug("No record found");
+ goto error;
+ }
+
+ if (!hdp_get_data_exchange_spec(rec, &data_spec))
+ goto error;
+
+ debug("Get data exchange spec %d", data_spec);
+error:
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Cannot get the remote SDP record");
+}
+
+static void health_device_free(struct hdp_device *device)
+{
+ if (device->conn) {
+ dbus_connection_unref(device->conn);
+ device->conn = NULL;
+ }
+
+ if (device->dev) {
+ btd_device_unref(device->dev);
+ device->dev = NULL;
+ }
+
+ g_free(device);
+}
+
+static void dev_path_unregister(void *data)
+{
+ struct hdp_device *device = data;
+
+
+ debug("Unregistered interface %s on path %s", HEALTH_DEVICE,
+ device_get_path(device->dev));
+ devices = g_slist_remove(devices, device);
+ health_device_free(device);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetHealthInstances", "", "a{sv}", get_health_instances },
+ { NULL }
+};
+
+static struct hdp_device *create_health_device(DBusConnection *conn,
+ struct btd_device *device)
+{
+ const gchar *path = device_get_path(device);
+ struct hdp_device *dev;
+
+ dev = g_new0(struct hdp_device, 1);
+ dev->conn = dbus_connection_ref(conn);
+ dev->dev = btd_device_ref(device);
+
+ if (!g_dbus_register_interface(conn, path,
+ HEALTH_DEVICE,
+ device_methods, NULL, NULL,
+ dev, dev_path_unregister)) {
+ error("D-Bus failed to register %s interface", HEALTH_DEVICE);
+ health_device_free(dev);
+ return NULL;
+ }
+
+ debug("Registered interface %s on path %s", HEALTH_DEVICE, path);
+ return dev;
+}
+
static void hdp_set_instance_id(struct hdp_instance *hdpi)
{
struct hdp_adapter *adapter = hdpi->adapter;
@@ -59,7 +155,7 @@ static void hdp_set_instance_id(struct hdp_instance *hdpi)
}
static DBusMessage *hdp_create_instance(DBusConnection *conn,
- DBusMessage *msg, void *user_data)
+ DBusMessage *msg, void *user_data)
{
struct hdp_adapter *adapter = user_data;
const char *path, *name;
@@ -185,13 +281,29 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
debug("HDP exit");
}
-int health_device_register(struct btd_device *device, const char *uuid)
+int hdp_device_register(DBusConnection *conn, struct btd_device *device)
{
- debug("HDP_DRIVER_PROBE with uuid %s", uuid);
+ struct hdp_device *hdp_dev;
+
+ hdp_dev = find_device(devices, device);
+ if (!hdp_dev) {
+ hdp_dev = create_health_device(conn, device);
+ if (!hdp_dev)
+ return -1;
+ devices = g_slist_append(devices, hdp_dev);
+ }
return 0;
}
-void health_device_unregister(struct btd_device *device)
+void hdp_device_unregister(struct btd_device *device)
{
- debug("TODO: Remove device");
+ struct hdp_device *hdp_dev;
+ const char *path;
+
+ hdp_dev = find_device(devices, device);
+ if (!hdp_dev)
+ return;
+
+ path = device_get_path(hdp_dev->dev);
+ g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
}
diff --git a/health/hdp.h b/health/hdp.h
index 0aae7b9..edb06a0 100644
--- a/health/hdp.h
+++ b/health/hdp.h
@@ -26,5 +26,5 @@
int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
-int health_device_register(struct btd_device *device, const char *uuid);
-void health_device_unregister(struct btd_device *device);
+int hdp_device_register(DBusConnection *conn, struct btd_device *device);
+void hdp_device_unregister(struct btd_device *device);
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 2db9adf..171910a 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -30,6 +30,10 @@
#include <glib.h>
#include "mcap_lib.h"
+#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
+#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
+#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+
#define HDP_SERVICE_NAME "Bluez HDP"
#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
#define HDP_SERVICE_PROVIDER "Bluez"
@@ -96,4 +100,10 @@ struct hdp_instance {
uint32_t sdp_handler; /* SDP record handler */
};
+struct hdp_device {
+ DBusConnection *conn; /* for name listener handling */
+ struct btd_device *dev; /* Device reference */
+ struct hdp_adapter *hdp_adapter; /* hdp_adapater */
+};
+
#endif /* __HDP_TYPES_H__ */
diff --git a/health/hdp_util.c b/health/hdp_util.c
index b386be5..816078a 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -838,3 +838,14 @@ error:
sdp_record_free(sdp_record);
return FALSE;
}
+
+gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
+{
+ sdp_data_t *exspec;
+
+ exspec = sdp_data_get(rec, SDP_ATTR_DATA_EXCHANGE_SPEC);
+ if (exspec->dtd != SDP_UINT8)
+ return FALSE;
+ *val = exspec->val.uint8;
+ return TRUE;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index fb114c7..0fdaaec 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -31,5 +31,7 @@
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
+gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+void hdp_instance_free(struct hdp_instance *hdpi);
#endif /* __HDP_UTIL_H__ */
diff --git a/health/manager.c b/health/manager.c
index 9b3b1a5..2f87db9 100644
--- a/health/manager.c
+++ b/health/manager.c
@@ -28,20 +28,19 @@
#endif
#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include <glib.h>
#include <gdbus.h>
-#include "adapter.h"
-#include "device.h"
+#include "hdp_types.h"
#include "logging.h"
#include "manager.h"
#include "hdp.h"
-#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
-#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
-#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+#include "device.h"
+#include "glib-helper.h"
static DBusConnection *connection = NULL;
@@ -63,22 +62,17 @@ static struct btd_adapter_driver hdp_adapter_driver = {
static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
{
- while (uuids) {
- health_device_register(device, uuids->data);
- uuids = uuids->next;
- }
-
- return 0;
+ return hdp_device_register(connection, device);
}
static void hdp_driver_remove(struct btd_device *device)
{
- health_device_unregister(device);
+ hdp_device_unregister(device);
}
static struct btd_device_driver hdp_device_driver = {
.name = "hdp-device-driver",
- .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
+ .uuids = BTD_UUIDS(HDP_UUID),
.probe = hdp_driver_probe,
.remove = hdp_driver_remove,
};
--
1.6.3.3
^ permalink raw reply related
* [PATCH 06/32] Add delete instance petition
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-6-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------
health/hdp_util.c | 35 +++++++++++++++++++++++++++-
2 files changed, 85 insertions(+), 14 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index ae6add4..6e3c2fc 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -34,7 +34,6 @@
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_INSTANCE_INTERFACE "org.bluez.HealthInstance"
#define HEALTH_DEVICE "org.bluez.HealthDevice"
static GSList *adapters = NULL;
@@ -147,6 +146,16 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
return dev;
}
+static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
+{
+ const struct hdp_instance *hdpi = instance;
+ const uint32_t *id = p;
+
+ if (hdpi->id == *id)
+ return 0;
+ return -1;
+}
+
static void hdp_set_instance_id(struct hdp_instance *hdpi)
{
struct hdp_adapter *adapter = hdpi->adapter;
@@ -187,24 +196,20 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->aname = g_strdup(name);
hdpi->apath = g_strdup(path);
hdpi->config = config;
- if (!config->svc_dsc)
- config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
- if (!config->svc_name)
- config->svc_name = g_strdup(HDP_SERVICE_NAME);
- if (!config->svc_prov)
- config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
hdp_set_instance_id(hdpi);
/* TODO: Create mcap instance */
if (!hdp_register_sdp_record(hdpi)) {
+ hdp_instance_free(hdpi);
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Session can't be registered");
}
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".HealthError",
- "Incomplete call yet");
+ adapter->instances = g_slist_prepend(adapter->instances, hdpi);
+ info("HDP instance created with path %d", hdpi->id);
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &hdpi->id,
+ DBUS_TYPE_INVALID);
error:
if (err) {
reply = g_dbus_create_error(msg,
@@ -218,16 +223,51 @@ error:
return reply;
}
+static DBusMessage *hdp_delete_instance(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_adapter *adapter = user_data;
+ struct hdp_instance *hdpi;
+ GSList *l;
+ const char *name;
+ uint32_t id;
+
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_INVALID))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+
+ l = g_slist_find_custom(adapter->instances, &id, hdp_instance_idcmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotFound",
+ "The session was not found");
+
+ name = dbus_message_get_sender(msg);
+ hdpi = l->data;
+ if (g_strcmp0(hdpi->aname, name) != 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "This session was created by an other process");
+ adapter->instances = g_slist_remove(adapter->instances, hdpi);
+ hdp_instance_free(hdpi);
+
+ debug("Stop HDP Session %d deleted", id);
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
static GDBusMethodTable hdp_methods[] = {
{ "CreateInstance", "oa{sv}", "u", hdp_create_instance },
+ { "DeleteInstance", "u", "", hdp_delete_instance },
{ NULL }
};
void hdp_delete_instance_iter(gpointer data, gpointer user_data)
{
- /* struct hdp_instance *hdpi = data; */
+ struct hdp_instance *hdpi = data;
- /* TODO: Create a free function */
+ hdp_instance_free(hdpi);
}
static void hdp_path_unregister(void *data)
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 816078a..b047aa2 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -109,6 +109,28 @@ static void free_config(struct hdp_config *config)
g_free(config);
}
+void hdp_instance_free(struct hdp_instance *hdpi)
+{
+ debug("HDP instance %d is deleted", hdpi->id);
+ /* TODO: Complete this part */
+ /*
+ g_slist_foreach(hdpi->devices, hdp_device_unregister, NULL);
+ g_slist_free(hdpi->devices);
+ hdpi->devices = NULL;
+ */
+
+ if (hdpi->sdp_handler)
+ remove_record_from_server(hdpi->sdp_handler);
+ /* TODO: stop mcap instance */
+ if (hdpi->apath)
+ g_free(hdpi->apath);
+ if (hdpi->aname)
+ g_free(hdpi->aname);
+ if (hdpi->config)
+ free_config(hdpi->config);
+ g_free(hdpi);
+}
+
static gboolean parse_dict_entry(struct dict_entry_func dict_context[],
DBusMessageIter *iter,
GError **err,
@@ -441,8 +463,17 @@ struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err)
"\"data_spec\" and \"end_point\" should be set or not");
goto error;
}
- if (!config->ds_present)
- goto error;
+ if (!config->ds_present) {
+ g_free(config);
+ return NULL;
+ }
+ if (!config->svc_dsc)
+ config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
+ if (!config->svc_name)
+ config->svc_name = g_strdup(HDP_SERVICE_NAME);
+ if (!config->svc_prov)
+ config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
+
debug("config->data_spec %d", config->data_spec);
g_slist_foreach(config->supp_fts, print_features, NULL);
return config;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 07/32] Add watcher to control client disconections to delete hdp instance
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-7-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 11 +++++++++++
health/hdp_types.h | 1 +
health/hdp_util.c | 2 ++
3 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 6e3c2fc..9ca2e52 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -163,6 +163,15 @@ static void hdp_set_instance_id(struct hdp_instance *hdpi)
hdpi->id = adapter->ic++;
}
+static void client_disconnected(DBusConnection *connection, void *user_data)
+{
+ struct hdp_instance *hdpi = user_data;
+ struct hdp_adapter *adapter = hdpi->adapter;
+ debug("Client disconnected from the bus, deleting hdp instance");
+ adapter->instances = g_slist_remove(adapter->instances, hdpi);
+ hdp_instance_free(hdpi);
+}
+
static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -197,6 +206,8 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->apath = g_strdup(path);
hdpi->config = config;
hdp_set_instance_id(hdpi);
+ hdpi->dbus_watcher = g_dbus_add_disconnect_watch(adapter->conn, name,
+ client_disconnected, hdpi, NULL);
/* TODO: Create mcap instance */
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 171910a..3bab4ea 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -98,6 +98,7 @@ struct hdp_instance {
char *aname; /* HDP agent name */
struct hdp_config *config; /* Configuration */
uint32_t sdp_handler; /* SDP record handler */
+ guint dbus_watcher; /* Client D-Bus conn watcher */
};
struct hdp_device {
diff --git a/health/hdp_util.c b/health/hdp_util.c
index b047aa2..42f28bf 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -119,6 +119,8 @@ void hdp_instance_free(struct hdp_instance *hdpi)
hdpi->devices = NULL;
*/
+ if (hdpi->dbus_watcher)
+ g_dbus_remove_watch(hdpi->adapter->conn, hdpi->dbus_watcher);
if (hdpi->sdp_handler)
remove_record_from_server(hdpi->sdp_handler);
/* TODO: stop mcap instance */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 08/32] Work in getting remote SDP records
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-8-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++--------
health/hdp_util.c | 5 +++
health/hdp_util.h | 1 +
3 files changed, 73 insertions(+), 13 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 9ca2e52..68bd809 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -31,6 +31,8 @@
#include "hdp_util.h"
#include "device.h"
+#include "glib-helper.h"
+
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
@@ -39,6 +41,11 @@
static GSList *adapters = NULL;
static GSList *devices = NULL;
+struct instances_aux {
+ struct hdp_device *device;
+ DBusMessage *msg;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -69,27 +76,73 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct instances_aux *cb_data = user_data;
+ DBusMessage *msg = cb_data->msg;
+ struct hdp_device *device = cb_data->device;
+ DBusMessage *reply;
+ sdp_record_t *rec;
+ sdp_list_t *l;
+ guint8 data_spec;
+ GSList *end_points;
+
+ g_free(cb_data);
+
+ if (err != 0) {
+ error("Error getting sink records");
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ g_dbus_send_message(device->conn, reply);
+ return;
+ }
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ debug("Record found 0x%x", rec->handle);
+ /* TODO: Check record */
+ if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
+ error("Error getting data exchange info");
+ continue;
+ }
+ end_points = hdp_get_end_points(rec);
+ if (!end_points) {
+ error("Error getting end points");
+ continue;
+ }
+ debug("Get data exchange spec %d", data_spec);
+ }
+
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Not implemented yet");
+ g_dbus_send_message(device->conn, reply);
+}
+
static DBusMessage *get_health_instances(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
- const sdp_record_t *rec;
- guint8 data_spec;
+ struct btd_adapter *adapter;
+ struct instances_aux *cb_data;
+ bdaddr_t src, dst;
+ uuid_t uuid;
- rec = btd_device_get_record(device->dev, HDP_UUID);
+ adapter = device_get_adapter(device->dev);
+ adapter_get_address(adapter, &src);
+ device_get_address(device->dev, &dst);
- if (!rec) {
- debug("No record found");
- goto error;
- }
+ cb_data = g_new0(struct instances_aux, 1);
+ cb_data->device = device;
+ cb_data->msg = dbus_message_ref(msg);
- if (!hdp_get_data_exchange_spec(rec, &data_spec))
- goto error;
- debug("Get data exchange spec %d", data_spec);
-error:
+ bt_string2uuid(&uuid, HDP_UUID);
+ if (bt_search_service(&src, &dst, &uuid, sink_health_instances,
+ cb_data, NULL) == 0)
+ return NULL;
+
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
- "Cannot get the remote SDP record");
+ "Error getting remote information");
}
static void health_device_free(struct hdp_device *device)
@@ -119,7 +172,8 @@ static void dev_path_unregister(void *data)
}
static GDBusMethodTable device_methods[] = {
- { "GetHealthInstances", "", "a{sv}", get_health_instances },
+ { "GetHealthInstances", "", "a{sv}", get_health_instances,
+ G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 42f28bf..a6d09c5 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -781,6 +781,11 @@ static gboolean register_data_exchange_spec(struct hdp_config *config,
return TRUE;
}
+GSList *hdp_get_end_points(const sdp_record_t *rec)
+{
+ return NULL;
+}
+
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
diff --git a/health/hdp_util.h b/health/hdp_util.h
index 0fdaaec..beafa00 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -32,6 +32,7 @@
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 09/32] Adds functions to get remote suported features from its SDP record
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-9-git-send-email-santoscadenas@gmail.com>
---
health/hdp_util.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 69 insertions(+), 5 deletions(-)
diff --git a/health/hdp_util.c b/health/hdp_util.c
index a6d09c5..b59e4e3 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -781,11 +781,6 @@ static gboolean register_data_exchange_spec(struct hdp_config *config,
return TRUE;
}
-GSList *hdp_get_end_points(const sdp_record_t *rec)
-{
- return NULL;
-}
-
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
@@ -887,3 +882,72 @@ gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
*val = exspec->val.uint8;
return TRUE;
}
+
+static gint cmp_feat_mdep(gconstpointer a, gconstpointer b)
+{
+ const struct hdp_supp_fts *fts = a;
+ const guint8 *mdep = b;
+
+ if (fts->mdepid == *mdep)
+ return 0;
+ return -1;
+}
+
+static GSList *get_feature(GSList *epl, sdp_data_t *feat_seq)
+{
+ struct hdp_supp_fts *fts;
+ struct hdp_feature *feat;
+ GSList *l;
+ sdp_data_t *mdepid, *dtype, *role, *desc;
+
+ mdepid = feat_seq;
+ if (!mdepid || mdepid->dtd != SDP_UINT8)
+ return epl;
+ dtype = mdepid->next;
+ if (!dtype || dtype->dtd != SDP_UINT16)
+ return epl;
+ role = dtype->next;
+ if (!role || role->dtd != SDP_UINT8)
+ return epl;
+ desc = role->next;
+
+ l = g_slist_find_custom(epl, &mdepid->val.uint8, cmp_feat_mdep);
+ if (l) {
+ fts = l->data;
+ if (fts->role != role->val.uint8)
+ return epl;
+ } else {
+ fts = g_new0(struct hdp_supp_fts, 1);
+ fts->mdepid = mdepid->val.uint8;
+ fts->role = role->val.uint8;
+ epl = g_slist_prepend(epl, fts);
+ }
+
+ feat = g_new0(struct hdp_feature, 1);
+ feat->dtype = dtype->val.uint16;
+ if (desc && desc->dtd == SDP_TEXT_STR8)
+ feat->dscr = g_strdup(desc->val.str);
+ fts->features = g_slist_prepend(fts->features, feat);
+ return epl;
+}
+
+GSList *hdp_get_end_points(const sdp_record_t *rec)
+{
+ GSList *epl = NULL;
+ sdp_data_t *end_points, *l;
+
+ end_points = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
+
+ if (end_points->dtd != SDP_SEQ8)
+ return NULL;
+
+ for (l = end_points->val.dataseq; l; l = l->next) {
+ if (l->dtd != SDP_SEQ8)
+ continue;
+ epl = get_feature(epl, l->val.dataseq);
+ }
+
+ g_slist_foreach(epl, print_features, NULL);
+
+ return epl;
+}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 10/32] Insert end_point in array returned by get_health_instances
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-10-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--
health/hdp_util.c | 2 -
2 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 68bd809..6d18626 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -76,6 +76,43 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
+{
+ DBusMessageIter entry, array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, "end_points");
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ dbus_message_iter_close_container(&entry, &array);
+ dbus_message_iter_close_container(iter, &entry);
+}
+
+static void append_array_entry(DBusMessageIter *iter, uint32_t *handler,
+ uint8_t *spec, GSList *end_points)
+{
+ DBusMessageIter dict;
+
+ 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, &dict);
+
+ dict_append_entry(&dict, "id", DBUS_TYPE_UINT32, handler);
+ dict_append_entry(&dict, "data_spec", DBUS_TYPE_BYTE, spec);
+ append_dict_features(&dict, end_points);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
{
struct instances_aux *cb_data = user_data;
@@ -86,6 +123,7 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
sdp_list_t *l;
guint8 data_spec;
GSList *end_points;
+ DBusMessageIter iter, dict;
g_free(cb_data);
@@ -97,10 +135,22 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
return;
}
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
for (l = recs; l; l = l->next) {
rec = l->data;
debug("Record found 0x%x", rec->handle);
- /* TODO: Check record */
+
if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
error("Error getting data exchange info");
continue;
@@ -110,11 +160,15 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
error("Error getting end points");
continue;
}
- debug("Get data exchange spec %d", data_spec);
+ append_array_entry(&dict, &rec->handle, &data_spec,
+ end_points);
}
+ dbus_message_iter_close_container(&iter, &dict);
+/*
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Not implemented yet");
+*/
g_dbus_send_message(device->conn, reply);
}
@@ -172,7 +226,7 @@ static void dev_path_unregister(void *data)
}
static GDBusMethodTable device_methods[] = {
- { "GetHealthInstances", "", "a{sv}", get_health_instances,
+ { "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
diff --git a/health/hdp_util.c b/health/hdp_util.c
index b59e4e3..f6ab8e7 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -947,7 +947,5 @@ GSList *hdp_get_end_points(const sdp_record_t *rec)
epl = get_feature(epl, l->val.dataseq);
}
- g_slist_foreach(epl, print_features, NULL);
-
return epl;
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 11/32] Initial support for connecting instances
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-11-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 6d18626..44b3c8f 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -76,6 +76,16 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
+{
+ const struct hdp_instance *hdpi = instance;
+ const uint32_t *id = p;
+
+ if (hdpi->id == *id)
+ return 0;
+ return -1;
+}
+
static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
{
DBusMessageIter entry, array;
@@ -225,9 +235,40 @@ static void dev_path_unregister(void *data)
health_device_free(device);
}
+static DBusMessage *hdp_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ struct hdp_instance *hdpi;
+ uint32_t lid, rid;
+ GSList *l;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &lid,
+ DBUS_TYPE_UINT32, &rid,
+ DBUS_TYPE_INVALID)) {
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ }
+
+ l = g_slist_find_custom(device->hdp_adapter->instances, &lid,
+ hdp_instance_idcmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid local instance id");
+ hdpi = l->data;
+
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
+ "Function is not yet implemented");
+}
+
static GDBusMethodTable device_methods[] = {
{ "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
+ { "Connect", "uu", "o", hdp_connect, G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
@@ -235,33 +276,30 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
struct btd_device *device)
{
const gchar *path = device_get_path(device);
+ struct btd_adapter *adapter = device_get_adapter(device);
struct hdp_device *dev;
dev = g_new0(struct hdp_device, 1);
dev->conn = dbus_connection_ref(conn);
dev->dev = btd_device_ref(device);
+ dev->hdp_adapter = find_adapter(adapters, adapter);
+
+ if (!dev->hdp_adapter)
+ goto fail;
if (!g_dbus_register_interface(conn, path,
HEALTH_DEVICE,
device_methods, NULL, NULL,
dev, dev_path_unregister)) {
error("D-Bus failed to register %s interface", HEALTH_DEVICE);
- health_device_free(dev);
- return NULL;
+ goto fail;
}
debug("Registered interface %s on path %s", HEALTH_DEVICE, path);
return dev;
-}
-
-static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
-{
- const struct hdp_instance *hdpi = instance;
- const uint32_t *id = p;
-
- if (hdpi->id == *id)
- return 0;
- return -1;
+fail:
+ health_device_free(dev);
+ return NULL;
}
static void hdp_set_instance_id(struct hdp_instance *hdpi)
--
1.6.3.3
^ permalink raw reply related
* [PATCH 12/32] Complete the response dictionary in GetHealthInstances response
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-12-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 169 ++++++++++++++++++++++++++++++++++-------------------
health/hdp_util.c | 56 +++++++++++++++++-
health/hdp_util.h | 12 ++++
3 files changed, 175 insertions(+), 62 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 44b3c8f..abae2df 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -46,6 +46,12 @@ struct instances_aux {
DBusMessage *msg;
};
+struct health_instances_aux {
+ guint32 handler;
+ guint8 data_spec;
+ GSList *end_points;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -86,41 +92,114 @@ static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
return -1;
}
-static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
+static void fill_up_one_spec(DBusMessageIter *dict, gpointer data)
{
- DBusMessageIter entry, array;
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, "end_points");
-
- dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
- DBUS_TYPE_VARIANT_AS_STRING
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
-
- dbus_message_iter_close_container(&entry, &array);
- dbus_message_iter_close_container(iter, &entry);
+ struct hdp_feature *feature = data;
+
+ dict_append_entry(dict, "dtype", DBUS_TYPE_UINT16, &feature->dtype);
+ if (feature->dscr)
+ dict_append_entry(dict, "description", DBUS_TYPE_STRING,
+ &feature->dscr);
}
-static void append_array_entry(DBusMessageIter *iter, uint32_t *handler,
- uint8_t *spec, GSList *end_points)
+static void fill_up_specs(DBusMessageIter *dict, gpointer data)
{
- DBusMessageIter dict;
+ GSList *specs = data;
+ GSList *l;
+ struct hdp_feature *feature;
+
- 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, &dict);
+ for (l = specs; l; l = l->next) {
+ feature = l->data;
- dict_append_entry(&dict, "id", DBUS_TYPE_UINT32, handler);
- dict_append_entry(&dict, "data_spec", DBUS_TYPE_BYTE, spec);
- append_dict_features(&dict, end_points);
+ hdp_append_dict(dict, fill_up_one_spec, feature);
+ }
+}
+
+static void fill_up_specs_array(DBusMessageIter *array, gpointer data)
+{
+ hdp_append_array_of_dicts(array, fill_up_specs, data);
+}
- dbus_message_iter_close_container(iter, &dict);
+static void fill_up_one_end_point(DBusMessageIter *dict, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ const char *role;
+
+ if (fts->role == HDP_SOURCE)
+ role = HDP_SOURCE_ROLE_AS_STRING;
+ else if (fts->role == HDP_SINK)
+ role = HDP_SINK_ROLE_AS_STRING;
+
+ dict_append_entry(dict, "mdepid", DBUS_TYPE_BYTE, &fts->mdepid);
+ dict_append_entry(dict, "role", DBUS_TYPE_STRING, &role);
+ hdp_append_variant_array_entry(dict, "specs", fill_up_specs_array,
+ fts->features);
+}
+
+static void fill_up_end_points(DBusMessageIter *dict, gpointer data)
+{
+ GSList *end_points = data;
+ struct hdp_supp_fts *fts;
+ GSList *l;
+
+ for (l = end_points; l; l = l->next) {
+ fts = l->data;
+
+ if (fts->role != HDP_SOURCE && fts->role != HDP_SINK)
+ continue;
+
+ hdp_append_dict(dict, fill_up_one_end_point, fts);
+ }
+}
+
+static void fill_up_end_points_array(DBusMessageIter *iter, gpointer data)
+{
+ hdp_append_array_of_dicts(iter, fill_up_end_points, data);
+}
+
+static void fill_up_instance(DBusMessageIter *entry, gpointer data)
+{
+ struct health_instances_aux *aux = data;
+ guint32 handler = aux->handler;
+ guint8 data_spec = aux->data_spec;
+ GSList *end_points = aux->end_points;
+
+ dict_append_entry(entry, "id", DBUS_TYPE_UINT32, &handler);
+ dict_append_entry(entry, "data_spec", DBUS_TYPE_BYTE, &data_spec);
+ hdp_append_variant_array_entry(entry, "end_points",
+ fill_up_end_points_array, end_points);
+}
+
+static void fill_up_health_instances(DBusMessageIter *dict, gpointer data)
+{
+ sdp_list_t *recs = data;
+ sdp_record_t *rec;
+ sdp_list_t *l;
+ guint8 data_spec;
+ GSList *end_points;
+ struct health_instances_aux *aux;
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ debug("Record found 0x%x", rec->handle);
+
+ if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
+ error("Error getting data exchange info");
+ continue;
+ }
+ end_points = hdp_get_end_points(rec);
+ if (!end_points) {
+ error("Error getting end points");
+ continue;
+ }
+ aux = g_new0(struct health_instances_aux, 1);
+ aux->handler = rec->handle;
+ aux->data_spec = data_spec;
+ aux->end_points = end_points;
+ hdp_append_dict(dict, fill_up_instance, aux);
+ g_free(aux);
+ }
}
static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
@@ -129,11 +208,7 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
DBusMessage *msg = cb_data->msg;
struct hdp_device *device = cb_data->device;
DBusMessage *reply;
- sdp_record_t *rec;
- sdp_list_t *l;
- guint8 data_spec;
- GSList *end_points;
- DBusMessageIter iter, dict;
+ DBusMessageIter iter;
g_free(cb_data);
@@ -151,34 +226,8 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- for (l = recs; l; l = l->next) {
- rec = l->data;
- debug("Record found 0x%x", rec->handle);
+ hdp_append_array_of_dicts(&iter, fill_up_health_instances, recs);
- if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
- error("Error getting data exchange info");
- continue;
- }
- end_points = hdp_get_end_points(rec);
- if (!end_points) {
- error("Error getting end points");
- continue;
- }
- append_array_entry(&dict, &rec->handle, &data_spec,
- end_points);
- }
-
- dbus_message_iter_close_container(&iter, &dict);
-/*
- reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
- "Not implemented yet");
-*/
g_dbus_send_message(device->conn, reply);
}
diff --git a/health/hdp_util.c b/health/hdp_util.c
index f6ab8e7..4f50550 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -328,9 +328,9 @@ static gboolean parse_role(DBusMessageIter *iter, GError **err, gpointer data)
}
dbus_message_iter_get_basic(string, &role);
- if (g_strcmp0(role, "sink") == 0)
+ if (g_strcmp0(role, HDP_SINK_ROLE_AS_STRING) == 0)
fts->role = HDP_SINK;
- else if (g_strcmp0(role, "source") == 0)
+ else if (g_strcmp0(role, HDP_SOURCE_ROLE_AS_STRING) == 0)
fts->role = HDP_SOURCE;
else {
g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
@@ -949,3 +949,55 @@ GSList *hdp_get_end_points(const sdp_record_t *rec)
return epl;
}
+
+void hdp_append_array_of_dicts(DBusMessageIter *iter, hdp_dbus_fill_up fill_up,
+ gpointer user_data)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ fill_up(&dict, user_data);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+void hdp_append_dict(DBusMessageIter *iter, hdp_dbus_fill_up fill_up,
+ gpointer user_data)
+{
+ DBusMessageIter entry;
+
+ 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, &entry);
+
+ fill_up(&entry, user_data);
+
+ dbus_message_iter_close_container(iter, &entry);
+}
+
+void hdp_append_variant_array_entry(DBusMessageIter *iter, char *key,
+ hdp_dbus_fill_up fill_up, gpointer user_data)
+{
+ DBusMessageIter entry, array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ fill_up(&array, user_data);
+
+ dbus_message_iter_close_container(&entry, &array);
+ dbus_message_iter_close_container(iter, &entry);
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index beafa00..08e6471 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -29,10 +29,22 @@
#include <gdbus.h>
#include "hdp_types.h"
+#define HDP_SINK_ROLE_AS_STRING "sink"
+#define HDP_SOURCE_ROLE_AS_STRING "source"
+
+typedef void (*hdp_dbus_fill_up)(DBusMessageIter *iter, gpointer data);
+
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
+void hdp_append_array_of_dicts(DBusMessageIter *iter, hdp_dbus_fill_up fill_up,
+ gpointer user_data);
+void hdp_append_dict(DBusMessageIter *iter, hdp_dbus_fill_up fil_up,
+ gpointer user_data);
+void hdp_append_variant_array_entry(DBusMessageIter *iter, char *key,
+ hdp_dbus_fill_up fill_up, gpointer user_data);
+
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 13/32] Implement connection of health instances
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-13-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++---
health/hdp_util.c | 26 ++++++++++++++
health/hdp_util.h | 2 +
3 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index abae2df..f5487c2 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -52,6 +52,13 @@ struct health_instances_aux {
GSList *end_points;
};
+struct hdp_connection_cb {
+ struct hdp_device *device;
+ struct hdp_instance *hdpi;
+ uint32_t rem_id;
+ DBusMessage *msg;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -240,7 +247,7 @@ static DBusMessage *get_health_instances(DBusConnection *conn,
bdaddr_t src, dst;
uuid_t uuid;
- adapter = device_get_adapter(device->dev);
+ adapter = device->hdp_adapter->btd_adapter;
adapter_get_address(adapter, &src);
device_get_address(device->dev, &dst);
@@ -284,12 +291,82 @@ static void dev_path_unregister(void *data)
health_device_free(device);
}
+static sdp_record_t *get_record(sdp_list_t *recs, uint32_t handle)
+{
+ sdp_record_t *rec;
+ sdp_list_t *l;
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ if (rec->handle == handle)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
+{
+ struct hdp_connection_cb *cb_data = data;
+
+ /* TODO */
+ g_free(cb_data);
+}
+
+static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
+{
+ struct hdp_connection_cb *cb_data = data;
+ struct hdp_device *device = cb_data->device;
+ struct hdp_instance *hdpi = cb_data->hdpi;
+ GError *gerr = NULL;
+ uint32_t rid = cb_data->rem_id;
+ DBusMessage *msg = cb_data->msg;
+ DBusMessage *reply;
+ sdp_record_t *rec;
+ guint16 ccpsm, version;
+ bdaddr_t dst;
+
+ if (err != 0) {
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ goto fail;
+ }
+
+ rec = get_record(recs, rid);
+ if (!rec) {
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ goto fail;
+ }
+
+ if (!hdp_get_prot_desc_list(rec, &ccpsm, &version)) {
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote protocol descriptor list");
+ goto fail;
+ }
+
+ device_get_address(device->dev, &dst);
+ mcap_create_mcl(hdpi->mi, &dst, ccpsm, &gerr, hdp_mcl_connect_cb,
+ cb_data);
+ if (!gerr)
+ return;
+
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote protocol descriptor list");
+fail:
+ g_dbus_send_message(device->conn, reply);
+ g_free(cb_data);
+}
+
static DBusMessage *hdp_connect(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
- struct hdp_instance *hdpi;
+ struct hdp_connection_cb *cb_data;
+ struct btd_adapter *adapter;
+ bdaddr_t src, dst;
uint32_t lid, rid;
+ uuid_t uuid;
GSList *l;
if (!dbus_message_get_args(msg, NULL,
@@ -307,11 +384,24 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
"Invalid local instance id");
- hdpi = l->data;
+ cb_data = g_new0(struct hdp_connection_cb, 1);
+ cb_data->device = device;
+ cb_data->hdpi = l->data;
+ cb_data->rem_id = rid;
+ cb_data->msg = dbus_message_ref(msg);
- return g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
- "Function is not yet implemented");
+ adapter = device->hdp_adapter->btd_adapter;
+ adapter_get_address(adapter, &src);
+ device_get_address(device->dev, &dst);
+
+ bt_string2uuid(&uuid, HDP_UUID);
+ if (bt_search_service(&src, &dst, &uuid, connect_health_instance,
+ cb_data, NULL) == 0)
+ return NULL;
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
}
static GDBusMethodTable device_methods[] = {
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 4f50550..844cd8c 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -883,6 +883,32 @@ gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
return TRUE;
}
+gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
+ guint16 *version)
+{
+ if (!(psm || version))
+ return TRUE;
+
+ /* TODO:
+ sdp_data_t *pdl, *l;
+
+ exspec = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
+ if (exspec->dtd != SDP_SEQ8)
+ return FALSE;
+
+ for (l = pdl->val.dataseq; l; l = l->next) {
+ if (l->dtd != SDP_SEQ8)
+ continue;
+ epl = get_feature(epl, l->val.dataseq);
+ }
+ */
+ if (psm)
+ *psm = 0x1001;
+ if (version)
+ *version = 0x0100;
+ return TRUE;
+}
+
static gint cmp_feat_mdep(gconstpointer a, gconstpointer b)
{
const struct hdp_supp_fts *fts = a;
diff --git a/health/hdp_util.h b/health/hdp_util.h
index 08e6471..03a7256 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -37,6 +37,8 @@ typedef void (*hdp_dbus_fill_up)(DBusMessageIter *iter, gpointer data);
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
+ guint16 *version);
GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 14/32] Manage mcap instances
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-14-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 73 ++++++++++++++++++++++++++++++++++++++++------------
health/hdp_util.c | 3 +-
2 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index f5487c2..a15667b 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -457,6 +457,30 @@ static void client_disconnected(DBusConnection *connection, void *user_data)
hdp_instance_free(hdpi);
}
+static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_connected");
+}
+
+static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_reconnected");
+}
+
+static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_disconnected");
+}
+
+static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_uncached");
+}
+
static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -472,17 +496,24 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
dbus_message_iter_init(msg, &iter);
ctype = dbus_message_iter_get_arg_type(&iter);
if (ctype != DBUS_TYPE_OBJECT_PATH)
- goto error;
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
dbus_message_iter_get_basic(&iter, &path);
dbus_message_iter_next(&iter);
config = hdp_get_config(&iter, &err);
- if (err)
- goto error;
+ if (err) {
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments: %s", err->message);
+ g_error_free(err);
+ return reply;
+ }
name = dbus_message_get_sender(msg);
if (!name) {
- g_set_error(&err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
- "Can't get sender name");
- goto error;
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Can't get sender name");
}
hdpi = g_new0(struct hdp_instance, 1);
@@ -494,7 +525,20 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->dbus_watcher = g_dbus_add_disconnect_watch(adapter->conn, name,
client_disconnected, hdpi, NULL);
- /* TODO: Create mcap instance */
+ hdpi->mi = mcap_create_instance(adapter->btd_adapter, BT_IO_SEC_MEDIUM,
+ 0, 0, &err, mcl_connected,
+ mcl_reconnected, mcl_disconnected,
+ mcl_uncached, hdpi);
+ if (err)
+ goto error;
+
+ hdpi->ccpsm = mcap_get_ctrl_psm(hdpi->mi, &err);
+ if (err)
+ goto error;
+
+ hdpi->dcpsm = mcap_get_data_psm(hdpi->mi, &err);
+ if (err)
+ goto error;
if (!hdp_register_sdp_record(hdpi)) {
hdp_instance_free(hdpi);
@@ -503,19 +547,14 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
}
adapter->instances = g_slist_prepend(adapter->instances, hdpi);
- info("HDP instance created with path %d", hdpi->id);
+ debug("HDP instance created with id %d", hdpi->id);
return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &hdpi->id,
DBUS_TYPE_INVALID);
error:
- if (err) {
- reply = g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments: %s", err->message);
- g_error_free(err);
- } else
- reply = g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
+ reply = g_dbus_create_error(msg,ERROR_INTERFACE ".HealthError",
+ err->message);
+ g_error_free(err);
+ hdp_instance_free(hdpi);
return reply;
}
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 844cd8c..5ba61dc 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -123,7 +123,8 @@ void hdp_instance_free(struct hdp_instance *hdpi)
g_dbus_remove_watch(hdpi->adapter->conn, hdpi->dbus_watcher);
if (hdpi->sdp_handler)
remove_record_from_server(hdpi->sdp_handler);
- /* TODO: stop mcap instance */
+ if (hdpi->mi)
+ mcap_release_instance(hdpi->mi);
if (hdpi->apath)
g_free(hdpi->apath);
if (hdpi->aname)
--
1.6.3.3
^ permalink raw reply related
* [PATCH 15/32] Implement connect MCL callback in health instances connection
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-15-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 73 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index a15667b..0d3265f 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -33,6 +33,8 @@
#include "glib-helper.h"
+#include "../mcap/mcap.h"
+
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
@@ -305,12 +307,77 @@ static sdp_record_t *get_record(sdp_list_t *recs, uint32_t handle)
return NULL;
}
+static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl connected");
+}
+
+static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl deleted");
+}
+
+static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl aborted");
+}
+
+static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl closed");
+}
+
+static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl connection request");
+ return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mcl *mcl,
+ uint8_t mdepid, uint16_t mdlid,
+ uint8_t *conf, void *data)
+{
+ debug("TODO: Incomplete callback, mdl reconnection request");
+ return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
{
struct hdp_connection_cb *cb_data = data;
+ struct hdp_device *device = cb_data->device;
+ /* struct hdp_instance *hdpi = cb_data->hdpi; */
+ DBusMessage *msg = cb_data->msg;
+ GError *cberr = NULL;
+ DBusMessage *reply;
- /* TODO */
g_free(cb_data);
+
+ if (err)
+ goto fail;
+
+ /* Create and Register HealthLink interface */
+ mcap_mcl_set_cb(mcl, &cberr, NULL /*health_link*/,
+ MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
+ MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
+ MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
+ MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
+ MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
+ MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
+ MCAP_MDL_CB_INVALID);
+ if (cberr)
+ goto fail;
+ return;
+fail:
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
+ (err ? err->message : cberr->message));
+ if (!cberr)
+ g_error_free(cberr);
+ g_dbus_send_message(device->conn, reply);
}
static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
@@ -383,7 +450,7 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
if (!l)
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
- "Invalid local instance id");
+ "Invalid local health instance id");
cb_data = g_new0(struct hdp_connection_cb, 1);
cb_data->device = device;
@@ -400,6 +467,7 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
cb_data, NULL) == 0)
return NULL;
+ g_free(cb_data);
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Error getting remote information");
}
@@ -499,6 +567,7 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
"Invalid arguments in method call");
+
dbus_message_iter_get_basic(&iter, &path);
dbus_message_iter_next(&iter);
config = hdp_get_config(&iter, &err);
@@ -509,6 +578,7 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
g_error_free(err);
return reply;
}
+
name = dbus_message_get_sender(msg);
if (!name) {
return g_dbus_create_error(msg,
@@ -552,7 +622,7 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBUS_TYPE_INVALID);
error:
reply = g_dbus_create_error(msg,ERROR_INTERFACE ".HealthError",
- err->message);
+ err->message);
g_error_free(err);
hdp_instance_free(hdpi);
return reply;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 16/32] Register Health link int the bus when MCL is connected
From: Jose Antonio Santos Cadenas @ 2010-06-02 13:19 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas
In-Reply-To: <1275484768-25838-16-git-send-email-santoscadenas@gmail.com>
---
health/hdp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-----
health/hdp_types.h | 12 +++++++++-
2 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 0d3265f..88e7235 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -37,8 +37,9 @@
#include "../src/dbus-common.h"
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_DEVICE "org.bluez.HealthDevice"
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+#define HEALTH_LINK "org.bluez.HealthLink"
static GSList *adapters = NULL;
static GSList *devices = NULL;
@@ -101,6 +102,18 @@ static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
return -1;
}
+static void set_health_link_path(struct hdp_link *hdpl)
+{
+ char path[MAX_PATH_LENGTH + 1];
+
+ hdpl->id = hdpl->hdpi->hlc++;
+ snprintf(path, MAX_PATH_LENGTH, "%s/health_link_%d_%d",
+ adapter_get_path(hdpl->hdpi->adapter->btd_adapter),
+ hdpl->hdpi->id, hdpl->id);
+
+ hdpl->path = g_strdup(path);
+}
+
static void fill_up_one_spec(DBusMessageIter *dict, gpointer data)
{
struct hdp_feature *feature = data;
@@ -346,12 +359,23 @@ static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mcl *mcl,
return MCAP_REQUEST_NOT_SUPPORTED;
}
+static void health_link_path_unregister(void *data)
+{
+ /* struct hdp_link *hdpl = data */
+ /* TODO: Unregister hdp_link*/
+}
+
+static GDBusMethodTable health_link_methods[] = {
+ { NULL }
+};
+
static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
{
struct hdp_connection_cb *cb_data = data;
struct hdp_device *device = cb_data->device;
- /* struct hdp_instance *hdpi = cb_data->hdpi; */
+ struct hdp_instance *hdpi = cb_data->hdpi;
DBusMessage *msg = cb_data->msg;
+ struct hdp_link *hdpl = NULL;
GError *cberr = NULL;
DBusMessage *reply;
@@ -360,8 +384,13 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
if (err)
goto fail;
- /* Create and Register HealthLink interface */
- mcap_mcl_set_cb(mcl, &cberr, NULL /*health_link*/,
+ hdpl = g_new0(struct hdp_link, 1);
+ hdpl->hdpi = hdpi;
+ hdpl->dev = device;
+ hdpl->mcl = mcap_mcl_ref(mcl);
+ set_health_link_path(hdpl);
+
+ mcap_mcl_set_cb(mcl, &cberr, hdpl,
MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
@@ -369,14 +398,35 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
MCAP_MDL_CB_INVALID);
+
if (cberr)
goto fail;
+
+ if (!g_dbus_register_interface(hdpl->dev->conn, hdpl->path, HEALTH_LINK,
+ health_link_methods, NULL, NULL,
+ hdpl, health_link_path_unregister)) {
+ error("D-Bus failed to register %s interface to %s",
+ HEALTH_LINK, hdpl->path);
+ goto fail;
+ }
+
+ hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &hdpl->path,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(device->conn, reply);
return;
fail:
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
(err ? err->message : cberr->message));
- if (!cberr)
+ if (cberr) {
+ /* MCAP will close the MCL and won't cache it if we didn't
+ * increase the MCL reference counter during the callback. */
+ mcap_mcl_unref(hdpl->mcl);
+ g_free(hdpl->path);
+ g_free(hdpl);
g_error_free(cberr);
+ }
+
g_dbus_send_message(device->conn, reply);
}
@@ -421,8 +471,8 @@ static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Error getting remote protocol descriptor list");
fail:
- g_dbus_send_message(device->conn, reply);
g_free(cb_data);
+ g_dbus_send_message(device->conn, reply);
}
static DBusMessage *hdp_connect(DBusConnection *conn,
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 3bab4ea..05bfbfe 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -99,10 +99,20 @@ struct hdp_instance {
struct hdp_config *config; /* Configuration */
uint32_t sdp_handler; /* SDP record handler */
guint dbus_watcher; /* Client D-Bus conn watcher */
+ uint16_t hlc; /* Health link id. counter */
+};
+
+struct hdp_link {
+ struct hdp_instance *hdpi; /* HDP session */
+ struct hdp_device *dev; /* Health Device */
+ struct mcap_mcl *mcl; /* MCAP mcl */
+ GSList *channels; /* Data channels */
+ char *path; /* HDP link path */
+ uint32_t id; /* Health link id */
};
struct hdp_device {
- DBusConnection *conn; /* for name listener handling */
+ DBusConnection *conn; /* For name listener handling */
struct btd_device *dev; /* Device reference */
struct hdp_adapter *hdp_adapter; /* hdp_adapater */
};
--
1.6.3.3
^ 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