Linux bluetooth development
 help / color / mirror / Atom feed
* [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


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox