Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Marcel Holtmann @ 2013-09-21 16:19 UTC (permalink / raw)
  To: Ken O'Brien; +Cc: gustavo, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379718623-1845-1-git-send-email-kernel@kenobrien.org>

Hi Ken,

> Adding generic rule for broadcom devices to generic usb bluetooth driver on encountering another instance of Broadcom's BCM20702A0.
> 
> Relevant section from /sys/kernel/debug/usb/devices:
> 
> T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
> D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=050d ProdID=065a Rev= 1.12
> S:  Manufacturer=Broadcom Corp
> S:  Product=BCM20702A0
> S:  SerialNumber=0002723E2D29
> C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
> E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
> I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
> 
> Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> ---
> drivers/bluetooth/btusb.c | 1 +
> 1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 8e16f0a..6d33dca 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -111,6 +111,7 @@ static struct usb_device_id btusb_table[] = {
> 
> 	/*Broadcom devices with vendor specific id */
> 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> +	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },

this is not correct. These devices are Broadcom based, but they are actually from Belkin. Same as the controllers from Apple. So it needs its own line and a comment that mentions Belkin.

Regards

Marcel


^ permalink raw reply

* [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-20 23:10 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Adding generic rule for broadcom devices to generic usb bluetooth driver on encountering another instance of Broadcom's BCM20702A0.

Relevant section from /sys/kernel/debug/usb/devices:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..6d33dca 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -111,6 +111,7 @@ static struct usb_device_id btusb_table[] = {
 
 	/*Broadcom devices with vendor specific id */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
 
 	{ }	/* Terminating entry */
 };
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH v5 2/2] Bluetooth: btmrvl: add calibration data download support
From: Bing Zhao @ 2013-09-20 22:21 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, linux-wireless,
	Mike Frysinger, Hyuckjoo Lee, Bing Zhao, Amitkumar Karwar
In-Reply-To: <1379715667-22424-1-git-send-email-bzhao@marvell.com>

From: Amitkumar Karwar <akarwar@marvell.com>

A text file containing calibration data in hex format can
be provided at following path:

/lib/firmware/mrvl/sd8797_caldata.conf

The data will be downloaded to firmware during initialization.

Reviewed-by: Mike Frysinger <vapier@chromium.org>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Hyuckjoo Lee <hyuckjoo.lee@samsung.com>
---
v2: Remove module parameter. The calibration data will be downloaded
    only when the device speicific data file is provided.
    (Marcel Holtmann)
v3: Fix crash (misaligned memory access) on ARM
v4: Simplify white space parsing and save some CPU cycles (Mike Frysinger)
v5: Improvements in cal data parsing logic. Add explanatory comments.
    Replace GFP_ATOMIC flag with GFP_KERNEL (Mike Frysinger)

 drivers/bluetooth/btmrvl_drv.h  |   10 +++-
 drivers/bluetooth/btmrvl_main.c |  144 ++++++++++++++++++++++++++++++++++++++-
 drivers/bluetooth/btmrvl_sdio.c |    9 ++-
 drivers/bluetooth/btmrvl_sdio.h |    2 +
 4 files changed, 161 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index e776b8b..dcd3468 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -23,6 +23,8 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <net/bluetooth/bluetooth.h>
+#include <linux/ctype.h>
+#include <linux/firmware.h>
 
 #define BTM_HEADER_LEN			4
 #define BTM_UPLD_SIZE			2312
@@ -41,6 +43,8 @@ struct btmrvl_thread {
 struct btmrvl_device {
 	void *card;
 	struct hci_dev *hcidev;
+	struct device *dev;
+	const char *cal_data;
 
 	u8 dev_type;
 
@@ -92,6 +96,7 @@ struct btmrvl_private {
 #define BT_CMD_HOST_SLEEP_CONFIG	0x59
 #define BT_CMD_HOST_SLEEP_ENABLE	0x5A
 #define BT_CMD_MODULE_CFG_REQ		0x5B
+#define BT_CMD_LOAD_CONFIG_DATA		0x61
 
 /* Sub-commands: Module Bringup/Shutdown Request/Response */
 #define MODULE_BRINGUP_REQ		0xF1
@@ -117,10 +122,13 @@ struct btmrvl_private {
 #define PS_SLEEP			0x01
 #define PS_AWAKE			0x00
 
+#define BT_CMD_DATA_SIZE		32
+#define BT_CAL_DATA_SIZE		28
+
 struct btmrvl_cmd {
 	__le16 ocf_ogf;
 	u8 length;
-	u8 data[4];
+	u8 data[BT_CMD_DATA_SIZE];
 } __packed;
 
 struct btmrvl_event {
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index e352f8e..6eea188 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -57,8 +57,9 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
 		ocf = hci_opcode_ocf(opcode);
 		ogf = hci_opcode_ogf(opcode);
 
-		if (ocf == BT_CMD_MODULE_CFG_REQ &&
-					priv->btmrvl_dev.sendcmdflag) {
+		if ((ocf == BT_CMD_MODULE_CFG_REQ ||
+		     ocf == BT_CMD_LOAD_CONFIG_DATA) &&
+		    priv->btmrvl_dev.sendcmdflag) {
 			priv->btmrvl_dev.sendcmdflag = false;
 			priv->adapter->cmd_complete = true;
 			wake_up_interruptible(&priv->adapter->cmd_wait_q);
@@ -479,6 +480,142 @@ static int btmrvl_open(struct hci_dev *hdev)
 	return 0;
 }
 
+/*
+ * This function parses provided calibration data input. It should contain
+ * hex bytes separated by space or new line character. Here is an example.
+ * 00 1C 01 37 FF FF FF FF 02 04 7F 01
+ * CE BA 00 00 00 2D C6 C0 00 00 00 00
+ * 00 F0 00 00
+ */
+static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size)
+{
+	const u8 *s = src;
+	u8 *d = dst;
+	int ret;
+	u8 tmp[3];
+
+	tmp[2] = '\0';
+	while ((s - src) <= len - 2) {
+		if (isspace(*s) || *s == '\n') {
+			s++;
+			continue;
+		}
+
+		if (isxdigit(*s)) {
+			if ((d - dst) >= dst_size) {
+				BT_ERR("calibration data file too big!!!");
+				return -EINVAL;
+			}
+
+			memcpy(tmp, s, 2);
+
+			ret = kstrtou8(tmp, 16, d++);
+			if (ret < 0)
+				return ret;
+
+			s += 2;
+		} else {
+			return -EINVAL;
+		}
+	}
+	if (d == dst)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int btmrvl_load_cal_data(struct btmrvl_private *priv,
+				u8 *config_data)
+{
+	struct sk_buff *skb;
+	struct btmrvl_cmd *cmd;
+	int i;
+
+	skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct btmrvl_cmd *)skb->data;
+	cmd->ocf_ogf =
+		cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_LOAD_CONFIG_DATA));
+	cmd->length = BT_CMD_DATA_SIZE;
+	cmd->data[0] = 0x00;
+	cmd->data[1] = 0x00;
+	cmd->data[2] = 0x00;
+	cmd->data[3] = BT_CMD_DATA_SIZE - 4;
+
+	/* Swap cal-data bytes. Each four bytes are swapped. Considering 4
+	 * byte SDIO header offset, mapping of input and output bytes will be
+	 * {3, 2, 1, 0} -> {0+4, 1+4, 2+4, 3+4},
+	 * {7, 6, 5, 4} -> {4+4, 5+4, 6+4, 7+4} */
+	for (i = 4; i < BT_CMD_DATA_SIZE; i++)
+		cmd->data[i] = config_data[(i / 4) * 8 - 1 - i];
+
+	bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+	skb_put(skb, sizeof(*cmd));
+	skb->dev = (void *)priv->btmrvl_dev.hcidev;
+	skb_queue_head(&priv->adapter->tx_queue, skb);
+	priv->btmrvl_dev.sendcmdflag = true;
+	priv->adapter->cmd_complete = false;
+
+	print_hex_dump_bytes("Calibration data: ",
+			     DUMP_PREFIX_OFFSET, cmd->data, BT_CMD_DATA_SIZE);
+
+	wake_up_interruptible(&priv->main_thread.wait_q);
+	if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
+					      priv->adapter->cmd_complete,
+				       msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) {
+		BT_ERR("Timeout while loading calibration data");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int
+btmrvl_process_cal_cfg(struct btmrvl_private *priv, u8 *data, u32 size)
+{
+	u8 cal_data[BT_CAL_DATA_SIZE];
+	int ret;
+
+	ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data));
+	if (ret)
+		return ret;
+
+	ret = btmrvl_load_cal_data(priv, cal_data);
+	if (ret) {
+		BT_ERR("Fail to load calibrate data");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int btmrvl_cal_data_config(struct btmrvl_private *priv)
+{
+	const struct firmware *cfg;
+	int ret;
+	const char *cal_data = priv->btmrvl_dev.cal_data;
+
+	if (!cal_data)
+		return 0;
+
+	ret = request_firmware(&cfg, cal_data, priv->btmrvl_dev.dev);
+	if (ret < 0) {
+		BT_DBG("Failed to get %s file, skipping cal data download",
+		       cal_data);
+		ret = 0;
+		goto done;
+	}
+
+	ret = btmrvl_process_cal_cfg(priv, (u8 *)cfg->data, cfg->size);
+done:
+	if (cfg)
+		release_firmware(cfg);
+
+	return ret;
+}
+
 static int btmrvl_setup(struct hci_dev *hdev)
 {
 	struct btmrvl_private *priv = hci_get_drvdata(hdev);
@@ -489,6 +626,9 @@ static int btmrvl_setup(struct hci_dev *hdev)
 
 	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
 
+	if (btmrvl_cal_data_config(priv))
+		BT_ERR("Set cal data failed");
+
 	priv->btmrvl_dev.psmode = 1;
 	btmrvl_enable_ps(priv);
 
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index c526915..51e95ed 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -18,7 +18,6 @@
  * this warranty disclaimer.
  **/
 
-#include <linux/firmware.h>
 #include <linux/slab.h>
 
 #include <linux/mmc/sdio_ids.h>
@@ -102,6 +101,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
 	.helper		= "mrvl/sd8688_helper.bin",
 	.firmware	= "mrvl/sd8688.bin",
+	.cal_data	= NULL,
 	.reg		= &btmrvl_reg_8688,
 	.sd_blksz_fw_dl	= 64,
 };
@@ -109,6 +109,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8787_uapsta.bin",
+	.cal_data	= NULL,
 	.reg		= &btmrvl_reg_87xx,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -116,6 +117,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8797_uapsta.bin",
+	.cal_data	= "mrvl/sd8797_caldata.conf",
 	.reg		= &btmrvl_reg_87xx,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -123,6 +125,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8897_uapsta.bin",
+	.cal_data	= NULL,
 	.reg		= &btmrvl_reg_88xx,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -1006,6 +1009,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 		struct btmrvl_sdio_device *data = (void *) id->driver_data;
 		card->helper = data->helper;
 		card->firmware = data->firmware;
+		card->cal_data = data->cal_data;
 		card->reg = data->reg;
 		card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
 	}
@@ -1034,6 +1038,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 	}
 
 	card->priv = priv;
+	priv->btmrvl_dev.dev = &card->func->dev;
+	priv->btmrvl_dev.cal_data = card->cal_data;
 
 	/* Initialize the interface specific function pointers */
 	priv->hw_host_to_card = btmrvl_sdio_host_to_card;
@@ -1216,4 +1222,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sd8797_caldata.conf");
 MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 43d35a6..6872d9e 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -85,6 +85,7 @@ struct btmrvl_sdio_card {
 	u32 ioport;
 	const char *helper;
 	const char *firmware;
+	const char *cal_data;
 	const struct btmrvl_sdio_card_reg *reg;
 	u16 sd_blksz_fw_dl;
 	u8 rx_unit;
@@ -94,6 +95,7 @@ struct btmrvl_sdio_card {
 struct btmrvl_sdio_device {
 	const char *helper;
 	const char *firmware;
+	const char *cal_data;
 	const struct btmrvl_sdio_card_reg *reg;
 	u16 sd_blksz_fw_dl;
 };
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v5 1/2] Bluetooth: btmrvl: add setup handler
From: Bing Zhao @ 2013-09-20 22:21 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, linux-wireless,
	Mike Frysinger, Hyuckjoo Lee, Bing Zhao, Amitkumar Karwar

From: Amitkumar Karwar <akarwar@marvell.com>

Move initialization code to hdev's setup handler. New flag
setup_done is added to make sure that initialization is done only
during driver load time. Our firmware doesn't expect
re-initialization later when interface is re-enabled.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
v5: make use of hdev's setup handler (Marcel Holtmann)

 drivers/bluetooth/btmrvl_drv.h  |    1 +
 drivers/bluetooth/btmrvl_main.c |   23 +++++++++++++++++++++--
 drivers/bluetooth/btmrvl_sdio.c |    6 ------
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 27068d1..e776b8b 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -68,6 +68,7 @@ struct btmrvl_adapter {
 	wait_queue_head_t cmd_wait_q;
 	u8 cmd_complete;
 	bool is_suspended;
+	bool setup_done;
 };
 
 struct btmrvl_private {
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 9a9f518..e352f8e 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -479,6 +479,27 @@ static int btmrvl_open(struct hci_dev *hdev)
 	return 0;
 }
 
+static int btmrvl_setup(struct hci_dev *hdev)
+{
+	struct btmrvl_private *priv = hci_get_drvdata(hdev);
+	struct btmrvl_adapter *adapter = priv->adapter;
+
+	if (adapter->setup_done)
+		return 0;
+
+	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+
+	priv->btmrvl_dev.psmode = 1;
+	btmrvl_enable_ps(priv);
+
+	priv->btmrvl_dev.gpio_gap = 0xffff;
+	btmrvl_send_hscfg_cmd(priv);
+
+	adapter->setup_done = true;
+
+	return 0;
+}
+
 /*
  * This function handles the event generated by firmware, rx data
  * received from firmware, and tx data sent from kernel.
@@ -572,8 +592,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
 	hdev->flush = btmrvl_flush;
 	hdev->send = btmrvl_send_frame;
 	hdev->ioctl = btmrvl_ioctl;
-
-	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+	hdev->setup = btmrvl_setup;
 
 	hdev->dev_type = priv->btmrvl_dev.dev_type;
 
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 75c2626..c526915 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1046,12 +1046,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 		goto disable_host_int;
 	}
 
-	priv->btmrvl_dev.psmode = 1;
-	btmrvl_enable_ps(priv);
-
-	priv->btmrvl_dev.gpio_gap = 0xffff;
-	btmrvl_send_hscfg_cmd(priv);
-
 	return 0;
 
 disable_host_int:
-- 
1.7.3.4

^ permalink raw reply related

* Re: [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Marcel Holtmann @ 2013-09-20 19:24 UTC (permalink / raw)
  To: Ken O'Brien; +Cc: gustavo, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379704619-27691-1-git-send-email-kernel@kenobrien.org>

Hi Ken,

> Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> 
> It's another instance of Broadcom's BCM20702A0.
> 
> Relevant section from /sys/kernel/debug/usb/devices:
> 
> T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
> D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=050d ProdID=065a Rev= 1.12
> S:  Manufacturer=Broadcom Corp
> S:  Product=BCM20702A0
> S:  SerialNumber=0002723E2D29
> C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms

we might consider a generic rule for this:

	/* comment of the device vendor and type goes here */
        { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },

Regards

Marcel


^ permalink raw reply

* [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-20 19:24 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

It's another instance of Broadcom's BCM20702A0.

Relevant section from /sys/kernel/debug/usb/devices:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..fa05faf 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -105,7 +105,8 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x04ca, 0x2003) },
 	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x413c, 0x8197) },
-
+	{ USB_DEVICE(0x050d, 0x065a) },
+
 	/* Foxconn - Hon Hai */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
 
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-20 19:16 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

It's another instance of Broadcom's BCM20702A0.

Relevant section from /sys/kernel/debug/usb/devices:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..fa05faf 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -105,7 +105,8 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x04ca, 0x2003) },
 	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x413c, 0x8197) },
-
+	{ USB_DEVICE(0x050d, 0x065a) },
+
 	/* Foxconn - Hon Hai */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
 
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH] Bluetooth: Add hci_h4p driver
From: Pali Rohár @ 2013-09-20 19:01 UTC (permalink / raw)
  To: Marcel Holtmann, Gustavo Padovan, Johan Hedberg
  Cc: Pavel Machek, linux-kernel, linux-bluetooth, Ville Tervo,
	Pali Rohár

From: Ville Tervo <ville.tervo@nokia.com>

This driver adding support for Nokia N900 bluetooth hardware

Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
 drivers/bluetooth/Kconfig             |   10 +
 drivers/bluetooth/Makefile            |    2 +
 drivers/bluetooth/hci_h4p/Makefile    |    7 +
 drivers/bluetooth/hci_h4p/core.c      | 1085 +++++++++++++++++++++++++++++++++
 drivers/bluetooth/hci_h4p/fw-bcm.c    |  149 +++++
 drivers/bluetooth/hci_h4p/fw-csr.c    |  152 +++++
 drivers/bluetooth/hci_h4p/fw-ti1273.c |  113 ++++
 drivers/bluetooth/hci_h4p/fw.c        |  166 +++++
 drivers/bluetooth/hci_h4p/hci_h4p.h   |  238 ++++++++
 drivers/bluetooth/hci_h4p/uart.c      |  203 ++++++
 include/linux/bluetooth/hci_h4p.h     |   41 ++
 11 files changed, 2166 insertions(+)
 create mode 100644 drivers/bluetooth/hci_h4p/Makefile
 create mode 100644 drivers/bluetooth/hci_h4p/core.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw-bcm.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw-csr.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw-ti1273.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw.c
 create mode 100644 drivers/bluetooth/hci_h4p/hci_h4p.h
 create mode 100644 drivers/bluetooth/hci_h4p/uart.c
 create mode 100644 include/linux/bluetooth/hci_h4p.h

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 11a6104..95155c3 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -242,4 +242,14 @@ config BT_WILINK
 
 	  Say Y here to compile support for Texas Instrument's WiLink7 driver
 	  into the kernel or say M to compile it as module.
+
+config BT_HCIH4P
+	tristate "HCI driver with H4 Nokia extensions"
+	depends on BT && ARCH_OMAP
+	help
+	  Bluetooth HCI driver with H4 extensions.  This driver provides
+	  support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+	  Say Y here to compile support for h4 extended devices into the kernel
+	  or say M to compile it as module (hci_h4p).
 endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 4afae20..a5e6e19 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -30,3 +30,5 @@ hci_uart-$(CONFIG_BT_HCIUART_LL)	+= hci_ll.o
 hci_uart-$(CONFIG_BT_HCIUART_ATH3K)	+= hci_ath.o
 hci_uart-$(CONFIG_BT_HCIUART_3WIRE)	+= hci_h5.o
 hci_uart-objs				:= $(hci_uart-y)
+
+obj-y				+= hci_h4p/
diff --git a/drivers/bluetooth/hci_h4p/Makefile b/drivers/bluetooth/hci_h4p/Makefile
new file mode 100644
index 0000000..f20bd9a
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux Bluetooth HCI device drivers.
+#
+
+obj-$(CONFIG_BT_HCIH4P)		+= hci_h4p.o
+
+hci_h4p-objs := core.o fw.o uart.o fw-csr.o fw-bcm.o fw-ti1273.o
diff --git a/drivers/bluetooth/hci_h4p/core.c b/drivers/bluetooth/hci_h4p/core.c
new file mode 100644
index 0000000..7ed9d4e
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/core.c
@@ -0,0 +1,1085 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2010 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/bluetooth/hci_h4p.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "hci_h4p.h"
+
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->clocks_lock, flags);
+	if (enable && !*clock) {
+		NBT_DBG_POWER("Enabling %p\n", clock);
+		clk_prepare_enable(info->uart_fclk);
+		clk_prepare_enable(info->uart_iclk);
+		if (atomic_read(&info->clk_users) == 0)
+			hci_h4p_restore_regs(info);
+		atomic_inc(&info->clk_users);
+	}
+
+	if (!enable && *clock) {
+		NBT_DBG_POWER("Disabling %p\n", clock);
+		if (atomic_dec_and_test(&info->clk_users))
+			hci_h4p_store_regs(info);
+		clk_disable_unprepare(info->uart_fclk);
+		clk_disable_unprepare(info->uart_iclk);
+	}
+
+	*clock = enable;
+	spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+/* Power management functions */
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable)
+{
+	u8 v;
+
+	return;
+
+	v = hci_h4p_inb(info, UART_OMAP_SYSC);
+	v &= ~(UART_OMAP_SYSC_IDLEMASK);
+
+	if (enable)
+		v |= UART_OMAP_SYSC_SMART_IDLE;
+	else
+		v |= UART_OMAP_SYSC_NO_IDLE;
+
+	hci_h4p_outb(info, UART_OMAP_SYSC, v);
+}
+
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+	NBT_DBG_POWER("\n");
+
+	if (!info->pm_enabled)
+		return;
+
+	hci_h4p_smart_idle(info, 1);
+
+	info->bt_wakeup(0);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+	info->tx_enabled = 0;
+}
+
+void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+	NBT_DBG_POWER("\n");
+
+	if (!info->pm_enabled)
+		return;
+
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	info->tx_enabled = 1;
+	hci_h4p_smart_idle(info, 0);
+	info->bt_wakeup(1);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+		     UART_IER_THRI);
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+	if (!info->pm_enabled)
+		return;
+
+	info->rx_enabled = 0;
+
+	if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+		NBT_DBG("data ready postpone autorts");
+		return;
+	}
+
+	if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) {
+		NBT_DBG("trasmitter not empty postpone autorts");
+		return;
+	}
+
+	hci_h4p_set_rts(info, info->rx_enabled);
+	__hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	info->autorts = 0;
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+	if (!info->pm_enabled)
+		return;
+
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+	info->rx_enabled = 1;
+
+	hci_h4p_set_rts(info, 1);
+
+	if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) {
+		NBT_DBG("trasmitter not empty postpone autorts");
+		return;
+	}
+
+	if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+		NBT_DBG("data ready postpone autorts");
+		return;
+	}
+
+	__hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+	info->autorts = 1;
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+	struct hci_h4p_alive_hdr *alive_hdr;
+	struct hci_h4p_alive_msg *alive_cmd;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	NBT_DBG("Sending alive packet\n");
+
+	skb = bt_skb_alloc(HCI_H4P_ALIVE_HDR_SIZE + HCI_H4P_ALIVE_MSG_SIZE, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	alive_hdr = (void *) skb_put(skb, HCI_H4P_ALIVE_HDR_SIZE);
+	alive_hdr->dlen = HCI_H4P_ALIVE_MSG_SIZE;
+	alive_cmd = (void *) skb_put(skb, HCI_H4P_ALIVE_MSG_SIZE);
+	alive_cmd->message_id = HCI_H4P_ALIVE_IND_REQ;
+	alive_cmd->unused = 0x00;
+	*skb_push(skb, 1) = H4_ALIVE_PKT;
+
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+		     UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	NBT_DBG("Alive packet sent\n");
+
+	return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	struct hci_h4p_alive_hdr *alive_hdr = (void *) skb->data;
+	struct hci_h4p_alive_msg *alive_evt;
+
+	if (alive_hdr->dlen > skb->len) {
+		info->init_error = -EPROTO;
+		complete(&info->init_completion);
+		return;
+	}
+
+	alive_evt = (void *) skb_pull(skb, HCI_H4P_ALIVE_HDR_SIZE);
+
+	NBT_DBG("Received alive packet\n");
+	if (alive_evt->message_id != HCI_H4P_ALIVE_IND_RESP) {
+		dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+		info->init_error = -EINVAL;
+	}
+
+	complete(&info->init_completion);
+	kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info)
+{
+	struct hci_h4p_init_cmd *init_cmd;
+	struct hci_h4p_init_hdr *init_hdr;
+	struct sk_buff *skb;
+	unsigned long flags;
+	int err;
+
+	NBT_DBG("Sending negotiation..\n");
+
+	skb = bt_skb_alloc(HCI_H4P_INIT_HDR_SIZE + HCI_H4P_INIT_CMD_SIZE, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	init_hdr = (void *)skb_put(skb, HCI_H4P_INIT_HDR_SIZE);
+	init_hdr->dlen = HCI_H4P_INIT_CMD_SIZE;
+	init_cmd = (void *)skb_put(skb, HCI_H4P_INIT_CMD_SIZE);
+	init_cmd->ack = 0x00;
+	init_cmd->baudrate = cpu_to_le16(0x01a1);
+	init_cmd->unused = cpu_to_le16(0x0000);
+	init_cmd->mode = HCI_H4P_MODE;
+	init_cmd->sys_clk = cpu_to_le16(0x9600);
+	init_cmd->unused2 = cpu_to_le16(0x0000);
+	*skb_push(skb, 1) = H4_NEG_PKT;
+
+	hci_h4p_change_speed(info, INIT_SPEED);
+
+	hci_h4p_set_rts(info, 1);
+	info->init_error = 0;
+	init_completion(&info->init_completion);
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+				msecs_to_jiffies(1000)))
+		return -ETIMEDOUT;
+
+	if (info->init_error < 0)
+		return info->init_error;
+
+	/* Change to operational settings */
+	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	hci_h4p_set_rts(info, 0);
+	hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+	err = hci_h4p_wait_for_cts(info, 1, 100);
+	if (err < 0)
+		return err;
+
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+	init_completion(&info->init_completion);
+	err = hci_h4p_send_alive_packet(info);
+
+	if (err < 0)
+		return err;
+
+	if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+				msecs_to_jiffies(1000)))
+		return -ETIMEDOUT;
+
+	if (info->init_error < 0)
+		return info->init_error;
+
+	NBT_DBG("Negotiation succesful\n");
+	return 0;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+				       struct sk_buff *skb)
+{
+	struct hci_h4p_init_hdr *init_hdr = (void *) skb->data;
+	struct hci_h4p_init_evt *init_evt;
+
+	if (init_hdr->dlen > skb->len) {
+		kfree_skb(skb);
+		info->init_error = -EPROTO;
+		complete(&info->init_completion);
+		return;
+	}
+
+	init_evt = (void *)skb_pull(skb, HCI_H4P_INIT_HDR_SIZE);
+
+	if (init_evt->ack != HCI_H4P_ACK) {
+		dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+		info->init_error = -EINVAL;
+	}
+
+	info->man_id = init_evt->man_id;
+	info->ver_id = init_evt->ver_id;
+
+	complete(&info->init_completion);
+	kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+	long retval;
+
+	switch (pkt_type) {
+	case H4_EVT_PKT:
+		retval = HCI_EVENT_HDR_SIZE;
+		break;
+	case H4_ACL_PKT:
+		retval = HCI_ACL_HDR_SIZE;
+		break;
+	case H4_SCO_PKT:
+		retval = HCI_SCO_HDR_SIZE;
+		break;
+	case H4_NEG_PKT:
+		retval = HCI_H4P_INIT_HDR_SIZE;
+		break;
+	case H4_ALIVE_PKT:
+		retval = HCI_H4P_ALIVE_HDR_SIZE;
+		break;
+	case H4_RADIO_PKT:
+		retval = H4_RADIO_HDR_SIZE;
+		break;
+	default:
+		dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+		retval = -1;
+		break;
+	}
+
+	return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+					 struct sk_buff *skb)
+{
+	long retval = -1;
+	struct hci_event_hdr *evt_hdr;
+	struct hci_acl_hdr *acl_hdr;
+	struct hci_sco_hdr *sco_hdr;
+	struct hci_h4p_radio_hdr *radio_hdr;
+	struct hci_h4p_init_hdr *init_hdr;
+	struct hci_h4p_alive_hdr *alive_hdr;
+
+	switch (bt_cb(skb)->pkt_type) {
+	case H4_EVT_PKT:
+		evt_hdr = (struct hci_event_hdr *)skb->data;
+		retval = evt_hdr->plen;
+		break;
+	case H4_ACL_PKT:
+		acl_hdr = (struct hci_acl_hdr *)skb->data;
+		retval = le16_to_cpu(acl_hdr->dlen);
+		break;
+	case H4_SCO_PKT:
+		sco_hdr = (struct hci_sco_hdr *)skb->data;
+		retval = sco_hdr->dlen;
+		break;
+	case H4_RADIO_PKT:
+		radio_hdr = (struct hci_h4p_radio_hdr *)skb->data;
+		retval = radio_hdr->dlen;
+		break;
+	case H4_NEG_PKT:
+		init_hdr = (struct hci_h4p_init_hdr *)skb->data;
+		retval = init_hdr->dlen;
+		break;
+	case H4_ALIVE_PKT:
+		alive_hdr = (struct hci_h4p_alive_hdr *)skb->data;
+		retval = alive_hdr->dlen;
+		break;
+	}
+
+	return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+				      struct sk_buff *skb)
+{
+
+	if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+		NBT_DBG("fw_event\n");
+		if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+			hci_h4p_negotiation_packet(info, info->rx_skb);
+			return;
+		}
+		if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+			hci_h4p_alive_packet(info, info->rx_skb);
+			return;
+		}
+		hci_h4p_parse_fw_event(info, skb);
+	} else {
+		hci_recv_frame(skb);
+		NBT_DBG("Frame sent to upper layer\n");
+	}
+}
+
+static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte)
+{
+	switch (info->rx_state) {
+	case WAIT_FOR_PKT_TYPE:
+		bt_cb(info->rx_skb)->pkt_type = byte;
+		info->rx_count = hci_h4p_get_hdr_len(info, byte);
+		if (info->rx_count < 0) {
+			info->hdev->stat.err_rx++;
+			kfree_skb(info->rx_skb);
+			info->rx_skb = NULL;
+		} else {
+			info->rx_state = WAIT_FOR_HEADER;
+		}
+		break;
+	case WAIT_FOR_HEADER:
+		info->rx_count--;
+		*skb_put(info->rx_skb, 1) = byte;
+		if (info->rx_count != 0)
+			break;
+
+		info->rx_count = hci_h4p_get_data_len(info,
+				info->rx_skb);
+		if (info->rx_count > skb_tailroom(info->rx_skb)) {
+			dev_err(info->dev, "Too long frame.\n");
+			info->garbage_bytes = info->rx_count -
+				skb_tailroom(info->rx_skb);
+			kfree_skb(info->rx_skb);
+			info->rx_skb = NULL;
+			break;
+		}
+		info->rx_state = WAIT_FOR_DATA;
+		break;
+	case WAIT_FOR_DATA:
+		info->rx_count--;
+		*skb_put(info->rx_skb, 1) = byte;
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	if (info->rx_count == 0) {
+		/* H4+ devices should allways send word aligned
+		 * packets */
+		if (!(info->rx_skb->len % 2))
+			info->garbage_bytes++;
+		hci_h4p_recv_frame(info, info->rx_skb);
+		info->rx_skb = NULL;
+	}
+}
+
+static void hci_h4p_rx(unsigned long data)
+{
+	u8 byte;
+	struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+	NBT_DBG("rx woke up\n");
+
+	while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+		byte = hci_h4p_inb(info, UART_RX);
+		if (info->garbage_bytes) {
+			info->garbage_bytes--;
+			continue;
+		}
+		if (info->rx_skb == NULL) {
+			info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
+						    GFP_ATOMIC);
+			if (!info->rx_skb) {
+				dev_err(info->dev,
+					"No memory for new packet\n");
+				return;
+			}
+			info->rx_state = WAIT_FOR_PKT_TYPE;
+			info->rx_skb->dev = (void *)info->hdev;
+		}
+		info->hdev->stat.byte_rx++;
+		NBT_DBG_TRANSFER_NF("0x%.2x  ", byte);
+		hci_h4p_handle_byte(info, byte);
+	}
+
+	if (info->rx_enabled == info->autorts)
+		return;
+
+	if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+		return;
+
+	if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)
+		return;
+
+	hci_h4p_set_rts(info, info->rx_enabled);
+	__hci_h4p_set_auto_ctsrts(info, info->rx_enabled, UART_EFR_RTS);
+	info->autorts = info->rx_enabled;
+
+	/* Flush posted write to avoid spurious interrupts */
+	hci_h4p_inb(info, UART_OMAP_SCR);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_tx(unsigned long data)
+{
+	unsigned int sent = 0;
+	struct sk_buff *skb;
+	struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+	NBT_DBG("tx woke up\n");
+	NBT_DBG_TRANSFER("data ");
+
+	if (info->autorts != info->rx_enabled) {
+		NBT_DBG("rts unbalanced.. autorts %d rx_enabled %d", info->autorts, info->rx_enabled);
+		if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
+		    !(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) {
+			__hci_h4p_set_auto_ctsrts(info, info->rx_enabled,
+							  UART_EFR_RTS);
+			info->autorts = info->rx_enabled;
+			hci_h4p_set_rts(info, info->rx_enabled);
+			hci_h4p_set_clk(info, &info->rx_clocks_en,
+					info->rx_enabled);
+			NBT_DBG("transmitter empty. setinng into balance\n");
+		} else {
+			hci_h4p_outb(info, UART_OMAP_SCR,
+				     hci_h4p_inb(info, UART_OMAP_SCR) |
+				     UART_OMAP_SCR_EMPTY_THR);
+			NBT_DBG("transmitter/receiver was not empty waiting for next irq\n");
+			hci_h4p_set_rts(info, 1);
+			goto finish_tx;
+		}
+	}
+
+	skb = skb_dequeue(&info->txq);
+	if (!skb) {
+		/* No data in buffer */
+		NBT_DBG("skb ready\n");
+		if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+			hci_h4p_outb(info, UART_IER,
+				     hci_h4p_inb(info, UART_IER) &
+				     ~UART_IER_THRI);
+			hci_h4p_inb(info, UART_OMAP_SCR);
+			hci_h4p_disable_tx(info);
+			NBT_DBG("transmitter was empty. cleaning up\n");
+			return;
+		}
+		hci_h4p_outb(info, UART_OMAP_SCR,
+				hci_h4p_inb(info, UART_OMAP_SCR) |
+				UART_OMAP_SCR_EMPTY_THR);
+		NBT_DBG("transmitter was not empty waiting for next irq\n");
+		goto finish_tx;
+	}
+
+	/* Copy data to tx fifo */
+	while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+	       (sent < skb->len)) {
+		NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+		hci_h4p_outb(info, UART_TX, skb->data[sent]);
+		sent++;
+	}
+
+	info->hdev->stat.byte_tx += sent;
+	if (skb->len == sent) {
+		kfree_skb(skb);
+	} else {
+		skb_pull(skb, sent);
+		skb_queue_head(&info->txq, skb);
+	}
+
+	hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) &
+						     ~UART_OMAP_SCR_EMPTY_THR);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+						 UART_IER_THRI);
+
+finish_tx:
+	/* Flush posted write to avoid spurious interrupts */
+	hci_h4p_inb(info, UART_OMAP_SCR);
+
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+	struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+	u8 iir, msr;
+	int ret;
+
+	ret = IRQ_NONE;
+
+	iir = hci_h4p_inb(info, UART_IIR);
+	if (iir & UART_IIR_NO_INT)
+		return IRQ_HANDLED;
+
+	NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+	iir &= UART_IIR_ID;
+
+	if (iir == UART_IIR_MSI) {
+		msr = hci_h4p_inb(info, UART_MSR);
+		ret = IRQ_HANDLED;
+	}
+	if (iir == UART_IIR_RLSI) {
+		hci_h4p_inb(info, UART_RX);
+		hci_h4p_inb(info, UART_LSR);
+		ret = IRQ_HANDLED;
+	}
+
+	if (iir == UART_IIR_RDI) {
+		hci_h4p_rx((unsigned long)data);
+		ret = IRQ_HANDLED;
+	}
+
+	if (iir == UART_IIR_THRI) {
+		hci_h4p_tx((unsigned long)data);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+	struct hci_h4p_info *info = dev_inst;
+	int should_wakeup;
+	struct hci_dev *hdev;
+
+	if (!info->hdev)
+		return IRQ_HANDLED;
+
+	hdev = info->hdev;
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return IRQ_HANDLED;
+
+	should_wakeup = info->host_wakeup();
+	NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+
+	/* Check if wee have missed some interrupts */
+	if (info->rx_enabled == should_wakeup)
+		return IRQ_HANDLED;
+
+	if (should_wakeup)
+		hci_h4p_enable_rx(info);
+	else
+		hci_h4p_disable_rx(info);
+
+	return IRQ_HANDLED;
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+	int err;
+
+	err = hci_h4p_reset_uart(info);
+	if (err < 0) {
+		dev_err(info->dev, "Uart reset failed\n");
+		return err;
+	}
+	hci_h4p_init_uart(info);
+	hci_h4p_set_rts(info, 0);
+
+	info->reset(0);
+	info->bt_wakeup(1);
+	msleep(10);
+	info->reset(1);
+
+	err = hci_h4p_wait_for_cts(info, 1, 100);
+	if (err < 0) {
+		dev_err(info->dev, "No cts from bt chip\n");
+		return err;
+	}
+
+	hci_h4p_set_rts(info, 1);
+
+	return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+	struct hci_h4p_info *info;
+	info = hci_get_drvdata(hdev);
+
+	skb_queue_purge(&info->txq);
+
+	return 0;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+	struct hci_h4p_info *info;
+	int err;
+	struct sk_buff_head fw_queue;
+	unsigned long flags;
+
+	info = hci_get_drvdata(hdev);
+
+	if (test_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	info->rx_enabled = 1;
+	info->rx_state = WAIT_FOR_PKT_TYPE;
+	info->rx_count = 0;
+	info->garbage_bytes = 0;
+	info->rx_skb = NULL;
+	info->pm_enabled = 0;
+	init_completion(&info->fw_completion);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+	skb_queue_head_init(&fw_queue);
+
+	err = hci_h4p_reset(info);
+	if (err < 0)
+		goto err_clean;
+
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+	info->autorts = 1;
+	err = hci_h4p_send_negotiation(info);
+	if (err < 0)
+		goto err_clean;
+
+	skb_queue_head_init(&fw_queue);
+	err = hci_h4p_read_fw(info, &fw_queue);
+	if (err < 0) {
+		dev_err(info->dev, "Cannot read firmware\n");
+		return err;
+	}
+
+	/* FW image contains also unneeded negoation and alive msgs */
+	skb_dequeue(&fw_queue);
+	skb_dequeue(&fw_queue);
+
+	err = hci_h4p_send_fw(info, &fw_queue);
+	if (err < 0) {
+		dev_err(info->dev, "Sending firmware failed.\n");
+		goto err_clean;
+	}
+
+	info->pm_enabled = 1;
+
+	spin_lock_irqsave(&info->lock, flags);
+	info->rx_enabled = info->host_wakeup();
+	hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+	set_bit(HCI_RUNNING, &hdev->flags);
+
+	NBT_DBG("hci up and running\n");
+	return 0;
+
+err_clean:
+	hci_h4p_hci_flush(hdev);
+	hci_h4p_reset_uart(info);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+	info->reset(0);
+	info->bt_wakeup(0);
+	skb_queue_purge(&fw_queue);
+	kfree_skb(info->rx_skb);
+
+	return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+	struct hci_h4p_info *info = hci_get_drvdata(hdev);
+
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	hci_h4p_hci_flush(hdev);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+	hci_h4p_reset_uart(info);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+	info->reset(0);
+	info->bt_wakeup(0);
+	kfree_skb(info->rx_skb);
+
+	return 0;
+}
+
+static int hci_h4p_hci_send_frame(struct sk_buff *skb)
+{
+	struct hci_h4p_info *info;
+	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+	int err = 0;
+	unsigned long flags;
+
+	if (!hdev) {
+		printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+		return -ENODEV;
+	}
+
+	NBT_DBG("dev %p, skb %p\n", hdev, skb);
+
+	info = hci_get_drvdata(hdev);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+		dev_warn(info->dev, "Frame for non-running device\n");
+		return -EIO;
+	}
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	}
+
+	/* Push frame type to skb */
+	*skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+	/* We should allways send word aligned data to h4+ devices */
+	if (skb->len % 2) {
+		err = skb_pad(skb, 1);
+		if (!err)
+			*skb_put(skb, 1) = 0x00;
+	}
+	if (err)
+		return err;
+
+	spin_lock_irqsave(&info->lock, flags);
+	skb_queue_tail(&info->txq, skb);
+	hci_h4p_enable_tx(info);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	return 0;
+}
+
+static int hci_h4p_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,
+			     unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+	struct hci_dev *hdev;
+
+	/* Initialize and register HCI device */
+
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		dev_err(info->dev, "Can't allocate memory for device\n");
+		return -ENOMEM;
+	}
+	info->hdev = hdev;
+
+	hdev->bus = HCI_UART;
+	hci_set_drvdata(hdev, info);
+
+	hdev->open = hci_h4p_hci_open;
+	hdev->close = hci_h4p_hci_close;
+	hdev->flush = hci_h4p_hci_flush;
+	hdev->send = hci_h4p_hci_send_frame;
+	hdev->ioctl = hci_h4p_hci_ioctl;
+	set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+	SET_HCIDEV_DEV(hdev, info->dev);
+
+	if (hci_register_dev(hdev) < 0) {
+		dev_err(info->dev, "hci_register failed %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct hci_h4p_info *info = dev_get_drvdata(dev);
+	unsigned int bdaddr[6];
+	int ret, i;
+
+	ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+			&bdaddr[0], &bdaddr[1], &bdaddr[2],
+			&bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+	if (ret != 6)
+		return -EINVAL;
+
+	for (i = 0; i < 6; i++)
+		info->bd_addr[i] = bdaddr[i] & 0xff;
+
+	return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct hci_h4p_info *info = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+		       info->bd_addr[0], info->bd_addr[1], info->bd_addr[2],
+		       info->bd_addr[3], info->bd_addr[4], info->bd_addr[5]);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr,
+		   hci_h4p_store_bdaddr);
+
+static int hci_h4p_sysfs_create_files(struct device *dev)
+{
+	return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+static void hci_h4p_sysfs_remove_files(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_bdaddr);
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+	struct hci_h4p_platform_data *bt_plat_data;
+	struct hci_h4p_info *info;
+	int err;
+
+	dev_info(&pdev->dev, "Registering HCI H4P device\n");
+	info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = &pdev->dev;
+	info->pm_enabled = 0;
+	info->tx_enabled = 1;
+	info->rx_enabled = 1;
+	info->garbage_bytes = 0;
+	info->tx_clocks_en = 0;
+	info->rx_clocks_en = 0;
+	spin_lock_init(&info->lock);
+	spin_lock_init(&info->clocks_lock);
+	skb_queue_head_init(&info->txq);
+
+	if (pdev->dev.platform_data == NULL) {
+		dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+		kfree(info);
+		return -ENODATA;
+	}
+
+	bt_plat_data = pdev->dev.platform_data;
+	info->chip_type = 3;
+	info->bt_wakeup = bt_plat_data->bt_wu;
+	info->host_wakeup = bt_plat_data->host_wu;
+	info->reset = bt_plat_data->reset;
+	info->uart_base = bt_plat_data->uart_base;
+	info->host_wakeup_gpio = bt_plat_data->host_wu_gpio;
+
+	NBT_DBG("RESET gpio: %p\n", info->reset);
+	NBT_DBG("BTWU gpio: %p\n", info->bt_wakeup);
+	NBT_DBG("HOSTWU gpio: %p\n", info->host_wakeup);
+
+	info->irq = bt_plat_data->uart_irq;
+	err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED | IRQF_SHARED,
+			"hci_h4p", info);
+	if (err < 0) {
+		dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
+		goto cleanup;
+	}
+
+	err = request_irq(gpio_to_irq(info->host_wakeup_gpio),
+			  hci_h4p_wakeup_interrupt,  IRQF_TRIGGER_FALLING |
+			  IRQF_TRIGGER_RISING | IRQF_DISABLED,
+			  "hci_h4p_wkup", info);
+	if (err < 0) {
+		dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+			  gpio_to_irq(info->host_wakeup_gpio));
+		free_irq(info->irq, info);
+		goto cleanup;
+	}
+
+	err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
+	if (err < 0) {
+		dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
+				gpio_to_irq(info->host_wakeup_gpio));
+		free_irq(info->irq, info);
+		free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+		goto cleanup;
+	}
+
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	err = hci_h4p_reset_uart(info);
+	if (err < 0)
+		goto cleanup_irq;
+	hci_h4p_init_uart(info);
+	hci_h4p_set_rts(info, 0);
+	err = hci_h4p_reset(info);
+	hci_h4p_reset_uart(info);
+	if (err < 0)
+		goto cleanup_irq;
+	info->reset(0);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+	platform_set_drvdata(pdev, info);
+
+	if (hci_h4p_sysfs_create_files(info->dev) < 0) {
+		dev_err(info->dev, "failed to create sysfs files\n");
+		goto cleanup_irq;
+	}
+
+	if (hci_h4p_register_hdev(info) < 0) {
+		dev_err(info->dev, "failed to register hci_h4p hci device\n");
+		goto cleanup_sysfs;
+	}
+
+	return 0;
+
+cleanup_sysfs:
+	hci_h4p_sysfs_remove_files(info->dev);
+cleanup_irq:
+	free_irq(info->irq, (void *)info);
+	free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+cleanup:
+	info->reset(0);
+	kfree(info);
+	return err;
+
+}
+
+static int hci_h4p_remove(struct platform_device *pdev)
+{
+	struct hci_h4p_info *info;
+
+	info = platform_get_drvdata(pdev);
+
+	hci_h4p_sysfs_remove_files(info->dev);
+	hci_h4p_hci_close(info->hdev);
+	free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+	hci_unregister_dev(info->hdev);
+	hci_free_dev(info->hdev);
+	free_irq(info->irq, (void *) info);
+	kfree(info);
+
+	return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+	.probe		= hci_h4p_probe,
+	.remove		= hci_h4p_remove,
+	.driver		= {
+		.name	= "hci_h4p",
+	},
+};
+
+static int __init hci_h4p_init(void)
+{
+	int err = 0;
+
+	/* Register the driver with LDM */
+	err = platform_driver_register(&hci_h4p_driver);
+	if (err < 0)
+		printk(KERN_WARNING "failed to register hci_h4p driver\n");
+
+	return err;
+}
+
+static void __exit hci_h4p_exit(void)
+{
+	platform_driver_unregister(&hci_h4p_driver);
+}
+
+module_init(hci_h4p_init);
+module_exit(hci_h4p_exit);
+
+MODULE_ALIAS("platform:hci_h4p");
+MODULE_DESCRIPTION("Bluetooth h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
+MODULE_FIRMWARE(FW_NAME_CSR);
+MODULE_FIRMWARE(FW_NAME_TI);
+MODULE_FIRMWARE(FW_NAME_BCM);
diff --git a/drivers/bluetooth/hci_h4p/fw-bcm.c b/drivers/bluetooth/hci_h4p/fw-bcm.c
new file mode 100644
index 0000000..56684f8
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-bcm.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+	int not_valid;
+	int i;
+
+	not_valid = 1;
+	for (i = 0; i < 6; i++) {
+		if (info->bd_addr[i] != 0x00) {
+			not_valid = 0;
+			break;
+		}
+	}
+
+	if (not_valid) {
+		dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
+		/* When address is not valid, use some random but Nokia MAC */
+		memcpy(info->bd_addr, nokia_oui, 3);
+		get_random_bytes(info->bd_addr + 3, 3);
+	}
+
+	for (i = 0; i < 6; i++)
+		skb->data[9 - i] = info->bd_addr[i];
+
+	return 0;
+}
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	struct sk_buff *fw_skb;
+	int err;
+	unsigned long flags;
+
+	if (skb->data[5] != 0x00) {
+		dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+			skb->data[5]);
+		info->fw_error = -EPROTO;
+	}
+
+	kfree_skb(skb);
+
+	fw_skb = skb_dequeue(info->fw_q);
+	if (fw_skb == NULL || info->fw_error) {
+		complete(&info->fw_completion);
+		return;
+	}
+
+	if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) {
+		NBT_DBG_FW("Setting bluetooth address\n");
+		err = hci_h4p_bcm_set_bdaddr(info, fw_skb);
+		if (err < 0) {
+			kfree_skb(fw_skb);
+			info->fw_error = err;
+			complete(&info->fw_completion);
+			return;
+		}
+	}
+
+	skb_queue_tail(&info->txq, fw_skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue)
+{
+	struct sk_buff *skb;
+	unsigned long flags, time;
+
+	info->fw_error = 0;
+
+	NBT_DBG_FW("Sending firmware\n");
+
+	time = jiffies;
+
+	info->fw_q = fw_queue;
+	skb = skb_dequeue(fw_queue);
+	if (!skb)
+		return -ENODATA;
+
+	NBT_DBG_FW("Sending commands\n");
+
+	/*
+	 * Disable smart-idle as UART TX interrupts
+	 * are not wake-up capable
+	 */
+	hci_h4p_smart_idle(info, 0);
+
+	/* Check if this is bd_address packet */
+	init_completion(&info->fw_completion);
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	if (!wait_for_completion_timeout(&info->fw_completion,
+				msecs_to_jiffies(2000))) {
+		dev_err(info->dev, "No reply to fw command\n");
+		return -ETIMEDOUT;
+	}
+
+	if (info->fw_error) {
+		dev_err(info->dev, "FW error\n");
+		return -EPROTO;
+	}
+
+	NBT_DBG_FW("Firmware sent in %d msecs\n",
+		   jiffies_to_msecs(jiffies-time));
+
+	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	hci_h4p_set_rts(info, 0);
+	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+	return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-csr.c b/drivers/bluetooth/hci_h4p/fw-csr.c
new file mode 100644
index 0000000..af880d9
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-csr.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	/* Check if this is fw packet */
+	if (skb->data[0] != 0xff) {
+		hci_recv_frame(skb);
+		return;
+	}
+
+	if (skb->data[11] || skb->data[12]) {
+		dev_err(info->dev, "Firmware sending command failed\n");
+		info->fw_error = -EPROTO;
+	}
+
+	kfree_skb(skb);
+	complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue)
+{
+	static const u8 nokia_oui[3] = {0x00, 0x19, 0x4F};
+	struct sk_buff *skb;
+	unsigned int offset;
+	int retries, count, i, not_valid;
+	unsigned long flags;
+
+	info->fw_error = 0;
+
+	NBT_DBG_FW("Sending firmware\n");
+	skb = skb_dequeue(fw_queue);
+
+	if (!skb)
+		return -ENOMSG;
+
+	/* Check if this is bd_address packet */
+	if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+		offset = 21;
+		skb->data[offset + 1] = 0x00;
+		skb->data[offset + 5] = 0x00;
+
+		not_valid = 1;
+		for (i = 0; i < 6; i++) {
+			if (info->bd_addr[i] != 0x00) {
+				not_valid = 0;
+				break;
+			}
+		}
+
+		if (not_valid) {
+			dev_info(info->dev, "Valid bluetooth address not found,"
+					" setting some random\n");
+			/* When address is not valid, use some random */
+			memcpy(info->bd_addr, nokia_oui, 3);
+			get_random_bytes(info->bd_addr + 3, 3);
+		}
+
+		skb->data[offset + 7] = info->bd_addr[0];
+		skb->data[offset + 6] = info->bd_addr[1];
+		skb->data[offset + 4] = info->bd_addr[2];
+		skb->data[offset + 0] = info->bd_addr[3];
+		skb->data[offset + 3] = info->bd_addr[4];
+		skb->data[offset + 2] = info->bd_addr[5];
+	}
+
+	for (count = 1; ; count++) {
+		NBT_DBG_FW("Sending firmware command %d\n", count);
+		init_completion(&info->fw_completion);
+		skb_queue_tail(&info->txq, skb);
+		spin_lock_irqsave(&info->lock, flags);
+		hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+							 UART_IER_THRI);
+		spin_unlock_irqrestore(&info->lock, flags);
+
+		skb = skb_dequeue(fw_queue);
+		if (!skb)
+			break;
+
+		if (!wait_for_completion_timeout(&info->fw_completion,
+						 msecs_to_jiffies(1000))) {
+			dev_err(info->dev, "No reply to fw command\n");
+			return -ETIMEDOUT;
+		}
+
+		if (info->fw_error) {
+			dev_err(info->dev, "FW error\n");
+			return -EPROTO;
+		}
+	};
+
+	/* Wait for chip warm reset */
+	retries = 100;
+	while ((!skb_queue_empty(&info->txq) ||
+	       !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+	       retries--) {
+		msleep(10);
+	}
+	if (!retries) {
+		dev_err(info->dev, "Transmitter not empty\n");
+		return -ETIMEDOUT;
+	}
+
+	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+	if (hci_h4p_wait_for_cts(info, 1, 100)) {
+		dev_err(info->dev, "cts didn't deassert after final speed\n");
+		return -ETIMEDOUT;
+	}
+
+	retries = 100;
+	do {
+		init_completion(&info->init_completion);
+		hci_h4p_send_alive_packet(info);
+		retries--;
+	} while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+		 retries > 0);
+
+	if (!retries) {
+		dev_err(info->dev, "No alive reply after speed change\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-ti1273.c b/drivers/bluetooth/hci_h4p/fw-ti1273.c
new file mode 100644
index 0000000..d46c3a0
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-ti1273.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static struct sk_buff_head *fw_q;
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+			struct sk_buff *skb)
+{
+	struct sk_buff *fw_skb;
+	unsigned long flags;
+
+	if (skb->data[5] != 0x00) {
+		dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+			skb->data[5]);
+		info->fw_error = -EPROTO;
+	}
+
+	kfree_skb(skb);
+
+	fw_skb = skb_dequeue(fw_q);
+	if (fw_skb == NULL || info->fw_error) {
+		complete(&info->fw_completion);
+		return;
+	}
+
+	hci_h4p_enable_tx(info);
+	skb_queue_tail(&info->txq, fw_skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue)
+{
+	struct sk_buff *skb;
+	unsigned long flags, time;
+
+	info->fw_error = 0;
+
+	NBT_DBG_FW("Sending firmware\n");
+
+	time = jiffies;
+
+	fw_q = fw_queue;
+	skb = skb_dequeue(fw_queue);
+	if (!skb)
+		return -ENODATA;
+
+	NBT_DBG_FW("Sending commands\n");
+	/* Check if this is bd_address packet */
+	init_completion(&info->fw_completion);
+	hci_h4p_enable_tx(info);
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	if (!wait_for_completion_timeout(&info->fw_completion,
+				msecs_to_jiffies(40000))) {
+		dev_err(info->dev, "No reply to fw command\n");
+		return -ETIMEDOUT;
+	}
+
+	if (info->fw_error) {
+		dev_err(info->dev, "FW error\n");
+		return -EPROTO;
+	}
+
+	NBT_DBG_FW("Firmware sent in %d msecs\n",
+		   jiffies_to_msecs(jiffies-time));
+
+	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	hci_h4p_set_rts(info, 0);
+	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+	if (hci_h4p_wait_for_cts(info, 1, 100)) {
+		dev_err(info->dev,
+			"cts didn't go down after final speed change\n");
+		return -ETIMEDOUT;
+	}
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+	return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw.c b/drivers/bluetooth/hci_h4p/fw.c
new file mode 100644
index 0000000..b767a12
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw.c
@@ -0,0 +1,166 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+				 const struct firmware **fw_entry)
+{
+	int err;
+
+	fw_pos = 0;
+	NBT_DBG_FW("Opening %d/%d firmware\n", info->man_id, info->ver_id);
+	switch (info->man_id) {
+	case BT_CHIP_TI:
+		err = request_firmware(fw_entry, FW_NAME_TI, info->dev);
+		break;
+	case BT_CHIP_CSR:
+		err = request_firmware(fw_entry, FW_NAME_CSR, info->dev);
+		break;
+	case BT_CHIP_BCM:
+		err = request_firmware(fw_entry, FW_NAME_BCM, info->dev);
+		break;
+	default:
+		dev_err(info->dev, "Invalid chip type %d\n", info->man_id);
+		*fw_entry = NULL;
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+	release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+			       const struct firmware *fw_entry, gfp_t how)
+{
+	unsigned int cmd_len;
+
+	if (fw_pos >= fw_entry->size)
+		return 0;
+
+	if (fw_pos + 2 > fw_entry->size) {
+		dev_err(info->dev, "Corrupted firmware image 1\n");
+		return -EMSGSIZE;
+	}
+
+	cmd_len = fw_entry->data[fw_pos++];
+	cmd_len += fw_entry->data[fw_pos++] << 8;
+	if (cmd_len == 0)
+		return 0;
+
+	if (fw_pos + cmd_len > fw_entry->size) {
+		dev_err(info->dev, "Corrupted firmware image 2\n");
+		return -EMSGSIZE;
+	}
+
+	*skb = bt_skb_alloc(cmd_len, how);
+	if (!*skb) {
+		dev_err(info->dev, "Cannot reserve memory for buffer\n");
+		return -ENOMEM;
+	}
+	memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+	fw_pos += cmd_len;
+
+	return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+	const struct firmware *fw_entry = NULL;
+	struct sk_buff *skb = NULL;
+	int err;
+
+	err = hci_h4p_open_firmware(info, &fw_entry);
+	if (err < 0 || !fw_entry)
+		goto err_clean;
+
+	while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+		if (err < 0 || !skb)
+			goto err_clean;
+
+		skb_queue_tail(fw_queue, skb);
+	}
+
+err_clean:
+	hci_h4p_close_firmware(fw_entry);
+	return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+	int err;
+
+	switch (info->man_id) {
+	case BT_CHIP_CSR:
+		err = hci_h4p_bc4_send_fw(info, fw_queue);
+		break;
+	case BT_CHIP_TI:
+		err = hci_h4p_ti1273_send_fw(info, fw_queue);
+		break;
+	case BT_CHIP_BCM:
+		err = hci_h4p_bcm_send_fw(info, fw_queue);
+		break;
+	default:
+		dev_err(info->dev, "Don't know how to send firmware\n");
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	switch (info->man_id) {
+	case BT_CHIP_CSR:
+		hci_h4p_bc4_parse_fw_event(info, skb);
+		break;
+	case BT_CHIP_TI:
+		hci_h4p_ti1273_parse_fw_event(info, skb);
+		break;
+	case BT_CHIP_BCM:
+		hci_h4p_bcm_parse_fw_event(info, skb);
+		break;
+	default:
+		dev_err(info->dev, "Don't know how to parse fw event\n");
+		info->fw_error = -EINVAL;
+	}
+
+	return;
+}
diff --git a/drivers/bluetooth/hci_h4p/hci_h4p.h b/drivers/bluetooth/hci_h4p/hci_h4p.h
new file mode 100644
index 0000000..ebafd37
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/hci_h4p.h
@@ -0,0 +1,238 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2010 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#define BT_CHIP_CSR		0x02
+#define BT_CHIP_TI		0x30
+#define BT_CHIP_BCM		0x04
+
+#define FW_NAME_CSR		"bc4fw.bin"
+#define FW_NAME_TI		"ti1273.bin"
+#define FW_NAME_BCM		"bcmfw.bin"
+
+#define UART_SYSC_OMAP_RESET	0x03
+#define UART_SYSS_RESETDONE	0x01
+#define UART_OMAP_SCR_EMPTY_THR	0x08
+#define UART_OMAP_SCR_WAKEUP	0x10
+#define UART_OMAP_SSR_WAKEUP	0x02
+#define UART_OMAP_SSR_TXFULL	0x01
+
+#define UART_OMAP_SYSC_IDLEMODE		0x03
+#define UART_OMAP_SYSC_IDLEMASK		(3 << UART_OMAP_SYSC_IDLEMODE)
+
+#define UART_OMAP_SYSC_FORCE_IDLE	(0 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_NO_IDLE		(1 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_SMART_IDLE	(2 << UART_OMAP_SYSC_IDLEMODE)
+
+#define NBT_DBG(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_FW(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_POWER(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_TRANSFER(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_TRANSFER_NF(fmt, arg...) \
+		pr_debug(fmt "" , ## arg)
+
+#define NBT_DBG_DMA(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+struct hci_h4p_info {
+	struct hci_dev *hdev;
+	spinlock_t lock;
+
+	void __iomem *uart_base;
+	unsigned long uart_phys_base;
+	int irq;
+	struct device *dev;
+	u8 chip_type;
+	void (*bt_wakeup)(bool enable);
+	bool (*host_wakeup)(void);
+	void (*reset)(bool enable);
+	int host_wakeup_gpio;
+	int man_id;
+	int ver_id;
+
+	struct sk_buff_head fw_queue;
+	struct completion init_completion;
+	struct completion fw_completion;
+	int fw_error;
+	int init_error;
+
+	struct sk_buff_head txq;
+
+	struct sk_buff *rx_skb;
+	long rx_count;
+	unsigned long rx_state;
+	unsigned long garbage_bytes;
+
+	u8 bd_addr[6];
+	struct sk_buff_head *fw_q;
+
+	int pm_enabled;
+	int tx_enabled;
+	int autorts;
+	int rx_enabled;
+
+	int tx_clocks_en;
+	int rx_clocks_en;
+	spinlock_t clocks_lock;
+	struct clk *uart_iclk;
+	struct clk *uart_fclk;
+	atomic_t clk_users;
+	u16 dll;
+	u16 dlh;
+	u16 ier;
+	u16 mdr1;
+	u16 efr;
+};
+
+struct hci_h4p_radio_hdr {
+	__u8 evt;
+	__u8 dlen;
+} __attribute__ ((packed));
+
+
+struct hci_h4p_init_hdr {
+	__u8 dlen;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_HDR_SIZE 1
+
+struct hci_h4p_init_cmd {
+	__u8 ack;
+	__u16 baudrate;
+	__u16 unused;
+	__u8 mode;
+	__u16 sys_clk;
+	__u16 unused2;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_CMD_SIZE 10
+
+struct hci_h4p_init_evt {
+	__u8 ack;
+	__u16 baudrate;
+	__u16 unused;
+	__u8 mode;
+	__u16 sys_clk;
+	__u16 unused2;
+	__u8 man_id;
+	__u8 ver_id;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_EVT_SIZE 12
+
+struct hci_h4p_alive_hdr {
+	__u8 dlen;
+} __attribute__ ((packed));
+#define HCI_H4P_ALIVE_HDR_SIZE 1
+
+struct hci_h4p_alive_msg {
+	__u8 message_id;
+	__u8 unused;
+} __attribute__ ((packed));
+#define HCI_H4P_ALIVE_MSG_SIZE 2
+
+#define MAX_BAUD_RATE		921600
+#define BC4_MAX_BAUD_RATE	3692300
+#define UART_CLOCK		48000000
+#define BT_INIT_DIVIDER		320
+#define BT_BAUDRATE_DIVIDER	384000000
+#define BT_SYSCLK_DIV		1000
+#define INIT_SPEED		120000
+
+#define HCI_H4P_MODE		0x4c
+
+#define HCI_H4P_ACK		0x20
+#define HCI_H4P_NACK		0x40
+#define HCI_H4P_ALIVE_IND_REQ	0x55
+#define HCI_H4P_ALIVE_IND_RESP	0xCC
+
+#define H4_TYPE_SIZE		1
+#define H4_RADIO_HDR_SIZE	2
+
+/* H4+ packet types */
+#define H4_CMD_PKT		0x01
+#define H4_ACL_PKT		0x02
+#define H4_SCO_PKT		0x03
+#define H4_EVT_PKT		0x04
+#define H4_NEG_PKT		0x06
+#define H4_ALIVE_PKT		0x07
+#define H4_RADIO_PKT		0x08
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE	1
+#define WAIT_FOR_HEADER		2
+#define WAIT_FOR_DATA		3
+
+struct hci_fw_event {
+	struct hci_event_hdr hev;
+	struct hci_ev_cmd_complete cmd;
+	u8 status;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info,
+				struct sk_buff *skb);
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+				struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue);
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+				    struct sk_buff *skb);
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+			    struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+void hci_h4p_init_uart(struct hci_h4p_info *info);
+void hci_h4p_enable_tx(struct hci_h4p_info *info);
+void hci_h4p_store_regs(struct hci_h4p_info *info);
+void hci_h4p_restore_regs(struct hci_h4p_info *info);
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/bluetooth/hci_h4p/uart.c b/drivers/bluetooth/hci_h4p/uart.c
new file mode 100644
index 0000000..033825f
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/uart.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <linux/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+	__raw_writeb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+	return __raw_readb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+	u8 b;
+
+	b = hci_h4p_inb(info, UART_MCR);
+	if (active)
+		b |= UART_MCR_RTS;
+	else
+		b &= ~UART_MCR_RTS;
+	hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+			 int timeout_ms)
+{
+	unsigned long timeout;
+	int state;
+
+	timeout = jiffies + msecs_to_jiffies(timeout_ms);
+	for (;;) {
+		state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+		if (active) {
+			if (state)
+				return 0;
+		} else {
+			if (!state)
+				return 0;
+		}
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+		msleep(1);
+	}
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+	u8 lcr, b;
+
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, 0xbf);
+	b = hci_h4p_inb(info, UART_EFR);
+	if (on)
+		b |= which;
+	else
+		b &= ~which;
+	hci_h4p_outb(info, UART_EFR, b);
+	hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+	__hci_h4p_set_auto_ctsrts(info, on, which);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+	unsigned int divisor;
+	u8 lcr, mdr1;
+
+	NBT_DBG("Setting speed %lu\n", speed);
+
+	if (speed >= 460800) {
+		divisor = UART_CLOCK / 13 / speed;
+		mdr1 = 3;
+	} else {
+		divisor = UART_CLOCK / 16 / speed;
+		mdr1 = 0;
+	}
+
+	/* Make sure UART mode is disabled */
+	hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
+	hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
+	hci_h4p_outb(info, UART_DLM, divisor >> 8);
+	hci_h4p_outb(info, UART_LCR, lcr);
+
+	/* Make sure UART mode is enabled */
+	hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+	int count = 0;
+
+	/* Reset the  UART */
+	hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+	while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+		if (count++ > 100) {
+			dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+			return -ENODEV;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+
+void hci_h4p_store_regs(struct hci_h4p_info *info)
+{
+	u16 lcr = 0;
+
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, 0xBF);
+	info->dll = hci_h4p_inb(info, UART_DLL);
+	info->dlh = hci_h4p_inb(info, UART_DLM);
+	info->efr = hci_h4p_inb(info, UART_EFR);
+	hci_h4p_outb(info, UART_LCR, lcr);
+	info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
+	info->ier = hci_h4p_inb(info, UART_IER);
+}
+
+void hci_h4p_restore_regs(struct hci_h4p_info *info)
+{
+	u16 lcr = 0;
+
+	hci_h4p_init_uart(info);
+
+	hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, 0xBF);
+	hci_h4p_outb(info, UART_DLL, info->dll);    /* Set speed */
+	hci_h4p_outb(info, UART_DLM, info->dlh);
+	hci_h4p_outb(info, UART_EFR, info->efr);
+	hci_h4p_outb(info, UART_LCR, lcr);
+	hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
+	hci_h4p_outb(info, UART_IER, info->ier);
+}
+
+void hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+	u8 mcr, efr;
+
+	/* Enable and setup FIFO */
+	hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
+
+	hci_h4p_outb(info, UART_LCR, 0xbf);
+	efr = hci_h4p_inb(info, UART_EFR);
+	hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+	mcr = hci_h4p_inb(info, UART_MCR);
+	hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+	hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+			(3 << 6) | (0 << 4));
+	hci_h4p_outb(info, UART_LCR, 0xbf);
+	hci_h4p_outb(info, UART_TI752_TLR, 0xed);
+	hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+	hci_h4p_outb(info, UART_EFR, efr);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+	hci_h4p_outb(info, UART_MCR, 0x00);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+	hci_h4p_outb(info, UART_IER, UART_IER_RDI | UART_IER_RLSI);
+	hci_h4p_outb(info, UART_OMAP_WER, 0xff);
+	hci_h4p_outb(info, UART_OMAP_SYSC, (0 << 0) | (1 << 2) | (1 << 3));
+}
diff --git a/include/linux/bluetooth/hci_h4p.h b/include/linux/bluetooth/hci_h4p.h
new file mode 100644
index 0000000..ba1d764
--- /dev/null
+++ b/include/linux/bluetooth/hci_h4p.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Contact: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ *
+ */
+
+
+/**
+ * struct hci_h4p_platform data - hci_h4p Platform data structure
+ * @uart_base:	UART base address
+ * @uart_irq:	UART Interrupt number
+ * @host_wu:	Function hook determine if Host should wakeup or not.
+ * @bt_wu:	Function hook to enable/disable Bluetooth transmission
+ * @reset:	Function hook to set/clear reset conditiona
+ * @host_wu_gpio:	Gpio used to wakeup host
+ */
+struct hci_h4p_platform_data {
+	void *uart_base;
+	unsigned int uart_irq;
+	bool (*host_wu)(void);
+	void (*bt_wu)(bool);
+	void (*reset)(bool);
+	unsigned int host_wu_gpio;
+};
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 2/2] android: Android version of log.c
From: Frederic Danis @ 2013-09-20 12:24 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1379679871-29623-1-git-send-email-frederic.danis@linux.intel.com>

Add logging system to BlueZ Android daemon.
Android build will use android/log.c file while autotools build will use
src/log.c instead.
---
 Makefile.android   |    2 +-
 android/Android.mk |    1 +
 android/log.c      |  184 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 android/main.c     |   39 +++++++++++
 4 files changed, 225 insertions(+), 1 deletion(-)
 create mode 100644 android/log.c

diff --git a/Makefile.android b/Makefile.android
index 7b901ff..8f65dbf 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -2,6 +2,6 @@
 if ANDROID_DAEMON
 noinst_PROGRAMS += android/bluezd
 
-android_bluezd_SOURCES = android/main.c
+android_bluezd_SOURCES = android/main.c src/log.c
 android_bluezd_LDADD = @GLIB_LIBS@
 endif
diff --git a/android/Android.mk b/android/Android.mk
index 50f3c36..25099b3 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -8,6 +8,7 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
 	main.c \
+	log.c \
 
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, glib) \
diff --git a/android/log.c b/android/log.c
new file mode 100644
index 0000000..1f98196
--- /dev/null
+++ b/android/log.c
@@ -0,0 +1,184 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  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 <fcntl.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#define LOG_DEBUG	3
+#define LOG_INFO	4
+#define LOG_WARN	5
+#define LOG_ERR		6
+
+const char tag[] = "BlueZ";
+int system_fd;
+int detached;
+
+static void android_log(int pri, const char *fmt, va_list ap)
+{
+	char *msg;
+	struct iovec vec[3];
+
+	msg = g_strdup_vprintf(fmt, ap);
+
+	if (!detached) {
+		vec[0].iov_base = (void *) msg;
+		vec[0].iov_len = strlen(msg) + 1;
+		vec[1].iov_base = "\n";
+		vec[1].iov_len = 1;
+		writev(STDERR_FILENO, vec, 2);
+	}
+
+	if (system_fd == -1)
+		goto done;
+
+	vec[0].iov_base = (unsigned char *) &pri;
+	vec[0].iov_len = 1;
+	vec[1].iov_base = (void *) tag;
+	vec[1].iov_len = strlen(tag) + 1;
+	vec[2].iov_base = (void *) msg;
+	vec[2].iov_len = strlen(msg) + 1;
+
+	writev(system_fd, vec, 3);
+
+done:
+	g_free(msg);
+}
+
+void info(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_INFO, format, ap);
+
+	va_end(ap);
+}
+
+void warn(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_WARN, format, ap);
+
+	va_end(ap);
+}
+
+void error(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_ERR, format, ap);
+
+	va_end(ap);
+}
+
+void btd_debug(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_DEBUG, format, ap);
+
+	va_end(ap);
+}
+
+extern struct btd_debug_desc __start___debug[];
+extern struct btd_debug_desc __stop___debug[];
+
+static char **enabled = NULL;
+
+static gboolean is_enabled(struct btd_debug_desc *desc)
+{
+	int i;
+
+	if (enabled == NULL)
+		return 0;
+
+	for (i = 0; enabled[i] != NULL; i++)
+		if (desc->file != NULL && g_pattern_match_simple(enabled[i],
+							desc->file) == TRUE)
+			return 1;
+
+	return 0;
+}
+
+void __btd_enable_debug(struct btd_debug_desc *start,
+					struct btd_debug_desc *stop)
+{
+	struct btd_debug_desc *desc;
+
+	if (start == NULL || stop == NULL)
+		return;
+
+	for (desc = start; desc < stop; desc++) {
+		if (is_enabled(desc))
+			desc->flags |= BTD_DEBUG_FLAG_PRINT;
+	}
+}
+
+void __btd_toggle_debug(void)
+{
+	struct btd_debug_desc *desc;
+
+	for (desc = __start___debug; desc < __stop___debug; desc++)
+		desc->flags |= BTD_DEBUG_FLAG_PRINT;
+}
+
+void __btd_log_init(const char *debug, int detach)
+{
+	if (debug != NULL)
+		enabled = g_strsplit_set(debug, ":, ", 0);
+
+	__btd_enable_debug(__start___debug, __stop___debug);
+
+	detached = detach;
+
+	system_fd = open("/dev/log/system", O_WRONLY);
+
+	info("Bluetooth daemon %s", VERSION);
+}
+
+void __btd_log_cleanup(void)
+{
+	close(system_fd);
+	system_fd = -1;
+
+	g_strfreev(enabled);
+}
diff --git a/android/main.c b/android/main.c
index 37a64c1..ef62b3d 100644
--- a/android/main.c
+++ b/android/main.c
@@ -33,6 +33,7 @@
 
 #include <glib.h>
 
+#include "log.h"
 #include "hcid.h"
 
 #define SHUTDOWN_GRACE_SECONDS 10
@@ -58,19 +59,45 @@ static void signal_handler(int sig)
 	case SIGINT:
 	case SIGTERM:
 		if (__terminated == 0) {
+			info("Terminating");
 			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
 							quit_eventloop, NULL);
 		}
 
 		__terminated = 1;
 		break;
+
+	case SIGUSR2:
+		__btd_toggle_debug();
+		break;
 	}
 }
 
+static char *option_debug = NULL;
 static gboolean option_detach = TRUE;
 static gboolean option_version = FALSE;
 
+static void free_options(void)
+{
+	g_free(option_debug);
+	option_debug = NULL;
+}
+
+static gboolean parse_debug(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (value)
+		option_debug = g_strdup(value);
+	else
+		option_debug = g_strdup("*");
+
+	return TRUE;
+}
+
 static GOptionEntry options[] = {
+	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+				G_OPTION_ARG_CALLBACK, parse_debug,
+				"Specify debug options to enable", "DEBUG" },
 	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
 				G_OPTION_ARG_NONE, &option_detach,
 				"Run with logging in foreground", NULL },
@@ -110,10 +137,22 @@ int main(int argc, char *argv[])
 	sa.sa_handler = signal_handler;
 	sigaction(SIGINT, &sa, NULL);
 	sigaction(SIGTERM, &sa, NULL);
+	sigaction(SIGUSR2, &sa, NULL);
+
+	__btd_log_init(option_debug, option_detach);
+
+	/* no need to keep parsed option in memory */
+	free_options();
+
+	DBG("Entering main loop");
 
 	g_main_loop_run(event_loop);
 
 	g_main_loop_unref(event_loop);
 
+	info("Exit");
+
+	__btd_log_cleanup();
+
 	return 0;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 1/2] android: Add skeleton of BlueZ Android daemon
From: Frederic Danis @ 2013-09-20 12:24 UTC (permalink / raw)
  To: linux-bluetooth

Define local mapping to glib path, otherwise this has to be inside central
place in the build repository.

Retrieve Bluetooth version from configure.ac.
---
 .gitignore         |    2 +
 Android.mk         |    9 ++++
 Makefile.am        |    1 +
 Makefile.android   |    7 ++++
 android/Android.mk |   24 +++++++++++
 android/main.c     |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac       |    5 +++
 7 files changed, 167 insertions(+)
 create mode 100644 Android.mk
 create mode 100644 Makefile.android
 create mode 100644 android/Android.mk
 create mode 100644 android/main.c

diff --git a/.gitignore b/.gitignore
index 8a25a3e..331a18b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -98,3 +98,5 @@ unit/test-gobex-packet
 unit/test-gobex-transfer
 unit/test-*.log
 unit/test-*.trs
+
+android/bluezd
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..5ec3bb7
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH := $(call my-dir)
+
+# Retrieve BlueZ version from configure.ac file
+BLUEZ_VERSION := $(shell grep AC_INIT $(LOCAL_PATH)/configure.ac | tr -d ' ' | sed -e 's/.*(.*,\(.*\))/\1/')
+
+# Specify pathmap for glib
+pathmap_INCL += glib:external/bluetooth/glib
+
+include $(call all-subdir-makefiles)
diff --git a/Makefile.am b/Makefile.am
index 4e4b1c5..2c048bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -179,6 +179,7 @@ test_scripts =
 
 include Makefile.tools
 include Makefile.obexd
+include Makefile.android
 
 if HID2HCI
 rulesdir = @UDEV_DIR@/rules.d
diff --git a/Makefile.android b/Makefile.android
new file mode 100644
index 0000000..7b901ff
--- /dev/null
+++ b/Makefile.android
@@ -0,0 +1,7 @@
+
+if ANDROID_DAEMON
+noinst_PROGRAMS += android/bluezd
+
+android_bluezd_SOURCES = android/main.c
+android_bluezd_LDADD = @GLIB_LIBS@
+endif
diff --git a/android/Android.mk b/android/Android.mk
new file mode 100644
index 0000000..50f3c36
--- /dev/null
+++ b/android/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH := $(call my-dir)
+
+#
+# Android BlueZ daemon (bluezd)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	main.c \
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, glib) \
+	$(call include-path-for, glib)/glib \
+	$(LOCAL_PATH)/../src \
+
+LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
+
+LOCAL_SHARED_LIBRARIES := \
+	libglib \
+
+LOCAL_MODULE := bluezd
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/main.c b/android/main.c
new file mode 100644
index 0000000..37a64c1
--- /dev/null
+++ b/android/main.c
@@ -0,0 +1,119 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  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 <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "hcid.h"
+
+#define SHUTDOWN_GRACE_SECONDS 10
+
+static GMainLoop *event_loop;
+
+void btd_exit(void)
+{
+	g_main_loop_quit(event_loop);
+}
+
+static gboolean quit_eventloop(gpointer user_data)
+{
+	btd_exit();
+	return FALSE;
+}
+
+static void signal_handler(int sig)
+{
+	static unsigned int __terminated = 0;
+
+	switch (sig) {
+	case SIGINT:
+	case SIGTERM:
+		if (__terminated == 0) {
+			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
+							quit_eventloop, NULL);
+		}
+
+		__terminated = 1;
+		break;
+	}
+}
+
+static gboolean option_detach = TRUE;
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
+				G_OPTION_ARG_NONE, &option_detach,
+				"Run with logging in foreground", NULL },
+	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+				"Show version information and exit", NULL },
+	{ NULL }
+};
+
+int main(int argc, char *argv[])
+{
+	GOptionContext *context;
+	GError *err = NULL;
+	struct sigaction sa;
+
+	context = g_option_context_new(NULL);
+	g_option_context_add_main_entries(context, options, NULL);
+
+	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
+		if (err != NULL) {
+			g_printerr("%s\n", err->message);
+			g_error_free(err);
+		} else
+			g_printerr("An unknown error occurred\n");
+		exit(1);
+	}
+
+	g_option_context_free(context);
+
+	if (option_version == TRUE) {
+		printf("%s\n", VERSION);
+		exit(0);
+	}
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = signal_handler;
+	sigaction(SIGINT, &sa, NULL);
+	sigaction(SIGTERM, &sa, NULL);
+
+	g_main_loop_run(event_loop);
+
+	g_main_loop_unref(event_loop);
+
+	return 0;
+}
diff --git a/configure.ac b/configure.ac
index 41c2935..3b7a5d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -242,4 +242,9 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
 			[Directory for the configuration files])
 AC_SUBST(CONFIGDIR, "${configdir}")
 
+AC_ARG_ENABLE(android-daemon, AC_HELP_STRING([--enable-android-daemon],
+			[enable BlueZ Android daemon]),
+					[android_daemon=${enableval}])
+AM_CONDITIONAL(ANDROID_DAEMON, test "${android_daemon}" = "yes")
+
 AC_OUTPUT(Makefile src/bluetoothd.8 lib/bluez.pc)
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 22:44 UTC (permalink / raw)
  To: Ken O'Brien, Gustavo Padovan
  Cc: marcel, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379628457.2494.1.camel@mjolnir.site>

[-- Attachment #1: Type: text/plain, Size: 3629 bytes --]

 Apologies. This was supposed to be in the commit log. I'll resubmit
the patch and I notice it's another instance of an existing bcm
device. I'll update the patch accordingly. 
Ken

----- Original Message -----
From: "Ken O'Brien" 
To:"Gustavo Padovan" 
Cc:, , , 
Sent:Thu, 19 Sep 2013 23:07:37 +0100
Subject:Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf
usb bluetooth device

 Here is the output:

 T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
 P: Vendor=050d ProdID=065a Rev= 1.12
 S: Manufacturer=Broadcom Corp
 S: Product=BCM20702A0
 S: SerialNumber=0002723E2D29
 C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
 I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
 E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
 E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
 I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
 I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
 I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
 I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
 I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
 I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
 I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
 E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
 E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
 I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

 On Thu, 2013-09-19 at 14:24 -0500, Gustavo Padovan wrote:
 > Hi Ken,
 > 
 > 2013-09-19 Ken O'Brien :
 > 
 > > Belkin bluetooth device's usb device id added to generic usb
bluetooth driver.
 > > 
 > > Signed-off-by: Ken O'Brien 
 > > ---
 > > drivers/bluetooth/btusb.c | 3 +++
 > > 1 file changed, 3 insertions(+)
 > > 
 > > diff --git a/drivers/bluetooth/btusb.c
b/drivers/bluetooth/btusb.c
 > > index 8e16f0a..117b90c 100644
 > > --- a/drivers/bluetooth/btusb.c
 > > +++ b/drivers/bluetooth/btusb.c
 > > @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
 > > 
 > > /*Broadcom devices with vendor specific id */
 > > { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
 > > +
 > > + /* Belkin F8T065bf */
 > > + { USB_DEVICE(0x050d, 0x065a) },
 > 
 > Could you please add the output of /sys/kernel/debug/usb/devices
for this
 > bluetooth controller to the commit messages, like we do for any new
device id
 > we add to btusb. Thanks.
 > 
 > Gustavo
 > --
 > To unsubscribe from this list: send the line "unsubscribe
linux-kernel" in
 > the body of a message to majordomo@vger.kernel.org
 > More majordomo info at http://vger.kernel.org/majordomo-info.html
 > Please read the FAQ at http://www.tux.org/lkml/

 --
 To unsubscribe from this list: send the line "unsubscribe
linux-kernel" in
 the body of a message to majordomo@vger.kernel.org
 More majordomo info at http://vger.kernel.org/majordomo-info.html
 Please read the FAQ at http://www.tux.org/lkml/


[-- Attachment #2: Type: text/html, Size: 4834 bytes --]

^ permalink raw reply

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 22:07 UTC (permalink / raw)
  To: Gustavo Padovan; +Cc: marcel, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <20130919192403.GH4006@joana>

Here is the output:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)


On Thu, 2013-09-19 at 14:24 -0500, Gustavo Padovan wrote:
> Hi Ken,
> 
> 2013-09-19 Ken O'Brien <kernel@kenobrien.org>:
> 
> > Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> > 
> > Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> > ---
> >  drivers/bluetooth/btusb.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index 8e16f0a..117b90c 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
> >  
> >  	/*Broadcom devices with vendor specific id */
> >  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> > +
> > +	/* Belkin F8T065bf */
> > +	{ USB_DEVICE(0x050d, 0x065a) },
> 
> Could you please add the output of /sys/kernel/debug/usb/devices for this
> bluetooth controller to the commit messages, like we do for any new device id
> we add to btusb. Thanks.
> 
> 	Gustavo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



^ permalink raw reply

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 20:56 UTC (permalink / raw)
  To: Gustavo Padovan, Ken O'Brien, marcel, johan.hedberg,
	linux-bluetooth, linux-kernel
In-Reply-To: <20130919192403.GH4006@joana>

Sure thing. Here's the output:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

On Thu, Sep 19, 2013 at 02:24:03PM -0500, Gustavo Padovan wrote:
> Hi Ken,
> 
> 2013-09-19 Ken O'Brien <kernel@kenobrien.org>:
> 
> > Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> > 
> > Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> > ---
> >  drivers/bluetooth/btusb.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index 8e16f0a..117b90c 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
> >  
> >  	/*Broadcom devices with vendor specific id */
> >  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> > +
> > +	/* Belkin F8T065bf */
> > +	{ USB_DEVICE(0x050d, 0x065a) },
> 
> Could you please add the output of /sys/kernel/debug/usb/devices for this
> bluetooth controller to the commit messages, like we do for any new device id
> we add to btusb. Thanks.
> 
> 	Gustavo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Gustavo Padovan @ 2013-09-19 19:24 UTC (permalink / raw)
  To: Ken O'Brien; +Cc: marcel, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379610373-2640-1-git-send-email-kernel@kenobrien.org>

Hi Ken,

2013-09-19 Ken O'Brien <kernel@kenobrien.org>:

> Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> 
> Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> ---
>  drivers/bluetooth/btusb.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 8e16f0a..117b90c 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
>  
>  	/*Broadcom devices with vendor specific id */
>  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> +
> +	/* Belkin F8T065bf */
> +	{ USB_DEVICE(0x050d, 0x065a) },

Could you please add the output of /sys/kernel/debug/usb/devices for this
bluetooth controller to the commit messages, like we do for any new device id
we add to btusb. Thanks.

	Gustavo

^ permalink raw reply

* [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 17:21 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..117b90c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
 
 	/*Broadcom devices with vendor specific id */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+
+	/* Belkin F8T065bf */
+	{ USB_DEVICE(0x050d, 0x065a) },
 
 	{ }	/* Terminating entry */
 };
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 17:06 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..117b90c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
 
 	/*Broadcom devices with vendor specific id */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+
+	/* Belkin F8T065bf */
+	{ USB_DEVICE(0x050d, 0x065a) },
 
 	{ }	/* Terminating entry */
 };
-- 
1.8.1.4

^ permalink raw reply related

* Re: [PATCH] rfcomm: don't release the port in rfcomm_dev_state_change()
From: Gustavo Padovan @ 2013-09-19 16:24 UTC (permalink / raw)
  To: Gianluca Anzolin; +Cc: peter, marcel, linux-bluetooth, gregkh, jslaby
In-Reply-To: <1377620926-23370-1-git-send-email-gianluca@sottospazio.it>

Hi Gianluca,

2013-08-27 Gianluca Anzolin <gianluca@sottospazio.it>:

> When the dlc is closed, rfcomm_dev_state_change() tries to release the
> port in the case it cannot get a reference to the tty. However this is
> racy and not even needed.
> 
> Infact as Peter Hurley points out:
> 
> 1. Only consider dlcs that are 'stolen' from a connected socket, ie.
>    reused. Allocated dlcs cannot have been closed prior to port
>    activate and so for these dlcs a tty reference will always be avail
>    in rfcomm_dev_state_change() -- except for the conditions covered by
>    #2b below.
> 2. If a tty was at some point previously created for this rfcomm, then
>    either
>    (a) the tty reference is still avail, so rfcomm_dev_state_change()
>        will perform a hangup. So nothing to do, or,
>    (b) the tty reference is no longer avail, and the tty_port will be
>        destroyed by the last tty_port_put() in rfcomm_tty_cleanup.
>        Again, no action required.
> 3. Prior to obtaining the dlc lock in rfcomm_dev_add(),
>    rfcomm_dev_state_change() will not 'see' a rfcomm_dev so nothing to
>    do here.
> 4. After releasing the dlc lock in rfcomm_dev_add(),
>    rfcomm_dev_state_change() will 'see' an incomplete rfcomm_dev if a
>    tty reference could not be obtained. Again, the best thing to do here
>    is nothing. Any future attempted open() will block on
>    rfcomm_dev_carrier_raised(). The unconnected device will exist until
>    released by ioctl(RFCOMMRELEASEDEV).
> 
> The patch removes the aforementioned code and uses the
> tty_port_tty_hangup() helper to hangup the tty.
> 
> Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
> ---
>  net/bluetooth/rfcomm/tty.c | 35 ++---------------------------------
>  1 file changed, 2 insertions(+), 33 deletions(-)

Patch has been applied to bluetooth.git. Thanks.

	Gustavo

^ permalink raw reply

* Re: [PATCH 2/2] Bluetooth: Add event mask page 2 setting support
From: Gustavo Padovan @ 2013-09-19 15:22 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth
In-Reply-To: <1379061602-8290-3-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

2013-09-13 johan.hedberg@gmail.com <johan.hedberg@gmail.com>:

> From: Johan Hedberg <johan.hedberg@intel.com>
> 
> For those controller that support the HCI_Set_Event_Mask_Page_2 command
> we should include it in the init sequence. This patch implements sending
> of the command and enables the events in it based on supported features
> (currently only CSB is checked).
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  include/net/bluetooth/hci.h |  2 ++
>  net/bluetooth/hci_core.c    | 32 ++++++++++++++++++++++++++++++++
>  2 files changed, 34 insertions(+)

Patch has been applied to bluetooth-next. Thanks.

	Gustavo

^ permalink raw reply

* [PATCH v3 8/8] sdp: Decouple Device ID profile implementation
From: Szymon Janc @ 2013-09-19 14:11 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-9-git-send-email-szymon.janc@tieto.com>

Make DeviceID profile similar to other profiles implementations. Use
btd_profile for handling DeviceID profile while adding/removing
adapters. The nice drawback is that SDP code no longer depends on
main_opts.
---

Fixed missing g_slist_remove.

 Makefile.plugins             |   3 +
 profiles/deviceid/deviceid.c | 189 +++++++++++++++++++++++++++++++++++++++++++
 src/adapter.c                |  26 +++---
 src/adapter.h                |   3 +
 src/sdpd-server.c            |   4 -
 src/sdpd-service.c           |  58 -------------
 src/sdpd.h                   |   2 -
 7 files changed, 206 insertions(+), 79 deletions(-)
 create mode 100644 profiles/deviceid/deviceid.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 7c5f71d..df5d2a1 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -82,6 +82,9 @@ builtin_sources += profiles/scanparam/scan.c
 builtin_modules += deviceinfo
 builtin_sources += profiles/deviceinfo/deviceinfo.c
 
+builtin_modules += deviceid
+builtin_sources += profiles/deviceid/deviceid.c
+
 if EXPERIMENTAL
 builtin_modules += alert
 builtin_sources += profiles/alert/server.c
diff --git a/profiles/deviceid/deviceid.c b/profiles/deviceid/deviceid.c
new file mode 100644
index 0000000..1ace475
--- /dev/null
+++ b/profiles/deviceid/deviceid.c
@@ -0,0 +1,189 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation
+ *
+ *
+ *  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 <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "sdpd.h"
+#include "hcid.h"
+#include "adapter.h"
+#include "profile.h"
+#include "plugin.h"
+#include "log.h"
+
+struct deviceid_adapter {
+	struct btd_adapter *adapter;
+	uint32_t handle;
+};
+
+static GSList *deviceid_adapters = NULL;
+
+static struct deviceid_adapter *find_adapter(struct btd_adapter *adapter)
+{
+	GSList *list;
+
+	for (list = deviceid_adapters; list; list = list->next) {
+		struct deviceid_adapter *da = list->data;
+
+		if (da->adapter == adapter)
+			return da;
+	}
+
+	return NULL;
+}
+
+static sdp_record_t *create_record(uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
+{
+	const uint16_t spec = 0x0103;
+	const uint8_t primary = 1;
+	sdp_list_t *class_list, *group_list, *profile_list;
+	uuid_t class_uuid, group_uuid;
+	sdp_data_t *sdp_data, *primary_data, *source_data;
+	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record = sdp_record_alloc();
+
+	DBG("%04x:%04x:%04x:%04x", source, vendor, product, version);
+
+	record->handle = sdp_next_handle();
+
+	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
+	class_list = sdp_list_append(0, &class_uuid);
+	sdp_set_service_classes(record, class_list);
+	sdp_list_free(class_list, NULL);
+
+	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
+	group_list = sdp_list_append(NULL, &group_uuid);
+	sdp_set_browse_groups(record, group_list);
+	sdp_list_free(group_list, NULL);
+
+	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
+	profile.version = spec;
+	profile_list = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, profile_list);
+	sdp_list_free(profile_list, NULL);
+
+	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
+	sdp_attr_add(record, 0x0200, spec_data);
+
+	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+	sdp_attr_add(record, 0x0201, vendor_data);
+
+	product_data = sdp_data_alloc(SDP_UINT16, &product);
+	sdp_attr_add(record, 0x0202, product_data);
+
+	version_data = sdp_data_alloc(SDP_UINT16, &version);
+	sdp_attr_add(record, 0x0203, version_data);
+
+	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
+	sdp_attr_add(record, 0x0204, primary_data);
+
+	source_data = sdp_data_alloc(SDP_UINT16, &source);
+	sdp_attr_add(record, 0x0205, source_data);
+
+	return record;
+}
+
+static int deviceid_adapter_probe(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+	sdp_record_t *rec;
+	int ret;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	rec = create_record(main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	ret = adapter_service_add(adapter, rec);
+	if (ret < 0) {
+		sdp_record_free(rec);
+		return ret;
+	}
+
+	btd_adapter_set_did(adapter, main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	dadapter = g_new0(struct deviceid_adapter, 1);
+	dadapter->adapter = btd_adapter_ref(adapter);
+	dadapter->handle = rec->handle;
+
+	deviceid_adapters = g_slist_prepend(deviceid_adapters, dadapter);
+
+	return 0;
+}
+
+static void deviceid_adapter_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	dadapter = find_adapter(adapter);
+	if (!dadapter)
+		return;
+
+	deviceid_adapters = g_slist_remove(deviceid_adapters, dadapter);
+
+	adapter_service_remove(dadapter->adapter, dadapter->handle);
+
+	btd_adapter_unref(dadapter->adapter);
+	g_free(dadapter);
+}
+
+struct btd_profile deviceid_profile = {
+	.name		= "deviceid",
+	.adapter_probe	= deviceid_adapter_probe,
+	.adapter_remove	= deviceid_adapter_remove,
+};
+
+static int deviceid_init(void)
+{
+	if (main_opts.did_source == 0) {
+		info("Device ID information disabled");
+		return -1;
+	}
+
+	return btd_profile_register(&deviceid_profile);
+}
+
+static void deviceid_exit(void)
+{
+	btd_profile_unregister(&deviceid_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceid, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			deviceid_init, deviceid_exit)
diff --git a/src/adapter.c b/src/adapter.c
index b99bff9..ed4824c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3929,17 +3929,12 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
 	adapter->system_name = g_strdup(main_opts.name);
 	adapter->major_class = (main_opts.class & 0x001f00) >> 8;
 	adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
-	adapter->modalias = bt_modalias(main_opts.did_source,
-						main_opts.did_vendor,
-						main_opts.did_product,
-						main_opts.did_version);
 	adapter->discoverable_timeout = main_opts.discovto;
 	adapter->pairable_timeout = main_opts.pairto;
 
 	DBG("System name: %s", adapter->system_name);
 	DBG("Major class: %u", adapter->major_class);
 	DBG("Minor class: %u", adapter->minor_class);
-	DBG("Modalias: %s", adapter->modalias);
 	DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
 	DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
 
@@ -5566,14 +5561,23 @@ void adapter_foreach(adapter_cb func, gpointer user_data)
 	g_slist_foreach(adapters, (GFunc) func, user_data);
 }
 
-static int set_did(struct btd_adapter *adapter, uint16_t vendor,
-			uint16_t product, uint16_t version, uint16_t source)
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
 {
 	struct mgmt_cp_set_device_id cp;
 
 	DBG("hci%u source %x vendor %x product %x version %x",
 			adapter->dev_id, source, vendor, product, version);
 
+	g_free(adapter->modalias);
+	adapter->modalias = bt_modalias(source, vendor, product, version);
+
+	DBG("Modalias: %s", adapter->modalias);
+
+	g_dbus_emit_property_changed(dbus_conn, adapter->path,
+						ADAPTER_INTERFACE, "Modalias");
+
 	memset(&cp, 0, sizeof(cp));
 
 	cp.source = htobs(source);
@@ -5638,14 +5642,6 @@ static int adapter_register(struct btd_adapter *adapter)
 
 	adapter->initialized = TRUE;
 
-	if (main_opts.did_source) {
-		/* DeviceID record is added by sdpd-server before any other
-		 * record is registered. */
-		adapter_service_insert(adapter, sdp_record_find(0x10000));
-		set_did(adapter, main_opts.did_vendor, main_opts.did_product,
-				main_opts.did_version, main_opts.did_source);
-	}
-
 	DBG("Adapter %s registered", adapter->path);
 
 	return 0;
diff --git a/src/adapter.h b/src/adapter.h
index 5d124e7..a6fb340 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -113,6 +113,9 @@ void btd_adapter_unref(struct btd_adapter *adapter);
 
 void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 							uint8_t minor);
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version);
 
 struct btd_adapter_driver {
 	const char *name;
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index 7b1351f..de5aef1 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -238,10 +238,6 @@ int start_sdp_server(uint16_t mtu, uint32_t flags)
 		return -1;
 	}
 
-	if (main_opts.did_source > 0)
-		register_device_id(main_opts.did_source, main_opts.did_vendor,
-				main_opts.did_product, main_opts.did_version);
-
 	io = g_io_channel_unix_new(l2cap_sock);
 	g_io_channel_set_close_on_unref(io, TRUE);
 
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 09f6c0a..2da70b5 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -176,64 +176,6 @@ void register_server_service(void)
 	update_db_timestamp();
 }
 
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version)
-{
-	const uint16_t spec = 0x0103;
-	const uint8_t primary = 1;
-	sdp_list_t *class_list, *group_list, *profile_list;
-	uuid_t class_uuid, group_uuid;
-	sdp_data_t *sdp_data, *primary_data, *source_data;
-	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record = sdp_record_alloc();
-
-	DBG("Adding device id record for %04x:%04x:%04x:%04x",
-					source, vendor, product, version);
-
-	record->handle = sdp_next_handle();
-
-	sdp_record_add(BDADDR_ANY, record);
-	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
-	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
-
-	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
-	class_list = sdp_list_append(0, &class_uuid);
-	sdp_set_service_classes(record, class_list);
-	sdp_list_free(class_list, NULL);
-
-	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
-	group_list = sdp_list_append(NULL, &group_uuid);
-	sdp_set_browse_groups(record, group_list);
-	sdp_list_free(group_list, NULL);
-
-	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
-	profile.version = spec;
-	profile_list = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, profile_list);
-	sdp_list_free(profile_list, NULL);
-
-	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
-	sdp_attr_add(record, 0x0200, spec_data);
-
-	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
-	sdp_attr_add(record, 0x0201, vendor_data);
-
-	product_data = sdp_data_alloc(SDP_UINT16, &product);
-	sdp_attr_add(record, 0x0202, product_data);
-
-	version_data = sdp_data_alloc(SDP_UINT16, &version);
-	sdp_attr_add(record, 0x0203, version_data);
-
-	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
-	sdp_attr_add(record, 0x0204, primary_data);
-
-	source_data = sdp_data_alloc(SDP_UINT16, &source);
-	sdp_attr_add(record, 0x0205, source_data);
-
-	update_db_timestamp();
-}
-
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 {
 	sdp_data_t *data;
diff --git a/src/sdpd.h b/src/sdpd.h
index 3c6ee01..174a4d7 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -54,8 +54,6 @@ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
 
 void register_public_browse_group(void);
 void register_server_service(void);
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v2 8/8] sdp: Decouple Device ID profile implementation
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

Make DeviceID profile similar to other profiles implementations. Use
btd_profile for handling DeviceID profile while adding/removing
adapters. The nice drawback is that SDP code no longer depends on
main_opts.
---
 Makefile.plugins             |   3 +
 profiles/deviceid/deviceid.c | 187 +++++++++++++++++++++++++++++++++++++++++++
 src/adapter.c                |  26 +++---
 src/adapter.h                |   3 +
 src/sdpd-server.c            |   4 -
 src/sdpd-service.c           |  58 --------------
 src/sdpd.h                   |   2 -
 7 files changed, 204 insertions(+), 79 deletions(-)
 create mode 100644 profiles/deviceid/deviceid.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 7c5f71d..df5d2a1 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -82,6 +82,9 @@ builtin_sources += profiles/scanparam/scan.c
 builtin_modules += deviceinfo
 builtin_sources += profiles/deviceinfo/deviceinfo.c
 
+builtin_modules += deviceid
+builtin_sources += profiles/deviceid/deviceid.c
+
 if EXPERIMENTAL
 builtin_modules += alert
 builtin_sources += profiles/alert/server.c
diff --git a/profiles/deviceid/deviceid.c b/profiles/deviceid/deviceid.c
new file mode 100644
index 0000000..be5df80
--- /dev/null
+++ b/profiles/deviceid/deviceid.c
@@ -0,0 +1,187 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation
+ *
+ *
+ *  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 <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "sdpd.h"
+#include "hcid.h"
+#include "adapter.h"
+#include "profile.h"
+#include "plugin.h"
+#include "log.h"
+
+struct deviceid_adapter {
+	struct btd_adapter *adapter;
+	uint32_t handle;
+};
+
+static GSList *deviceid_adapters = NULL;
+
+static struct deviceid_adapter *find_adapter(struct btd_adapter *adapter)
+{
+	GSList *list;
+
+	for (list = deviceid_adapters; list; list = list->next) {
+		struct deviceid_adapter *da = list->data;
+
+		if (da->adapter == adapter)
+			return da;
+	}
+
+	return NULL;
+}
+
+static sdp_record_t *create_record(uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
+{
+	const uint16_t spec = 0x0103;
+	const uint8_t primary = 1;
+	sdp_list_t *class_list, *group_list, *profile_list;
+	uuid_t class_uuid, group_uuid;
+	sdp_data_t *sdp_data, *primary_data, *source_data;
+	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record = sdp_record_alloc();
+
+	DBG("%04x:%04x:%04x:%04x", source, vendor, product, version);
+
+	record->handle = sdp_next_handle();
+
+	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
+	class_list = sdp_list_append(0, &class_uuid);
+	sdp_set_service_classes(record, class_list);
+	sdp_list_free(class_list, NULL);
+
+	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
+	group_list = sdp_list_append(NULL, &group_uuid);
+	sdp_set_browse_groups(record, group_list);
+	sdp_list_free(group_list, NULL);
+
+	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
+	profile.version = spec;
+	profile_list = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, profile_list);
+	sdp_list_free(profile_list, NULL);
+
+	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
+	sdp_attr_add(record, 0x0200, spec_data);
+
+	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+	sdp_attr_add(record, 0x0201, vendor_data);
+
+	product_data = sdp_data_alloc(SDP_UINT16, &product);
+	sdp_attr_add(record, 0x0202, product_data);
+
+	version_data = sdp_data_alloc(SDP_UINT16, &version);
+	sdp_attr_add(record, 0x0203, version_data);
+
+	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
+	sdp_attr_add(record, 0x0204, primary_data);
+
+	source_data = sdp_data_alloc(SDP_UINT16, &source);
+	sdp_attr_add(record, 0x0205, source_data);
+
+	return record;
+}
+
+static int deviceid_adapter_probe(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+	sdp_record_t *rec;
+	int ret;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	rec = create_record(main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	ret = adapter_service_add(adapter, rec);
+	if (ret < 0) {
+		sdp_record_free(rec);
+		return ret;
+	}
+
+	btd_adapter_set_did(adapter, main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	dadapter = g_new0(struct deviceid_adapter, 1);
+	dadapter->adapter = btd_adapter_ref(adapter);
+	dadapter->handle = rec->handle;
+
+	deviceid_adapters = g_slist_prepend(deviceid_adapters, dadapter);
+
+	return 0;
+}
+
+static void deviceid_adapter_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	dadapter = find_adapter(adapter);
+	if (!dadapter)
+		return;
+
+	adapter_service_remove(dadapter->adapter, dadapter->handle);
+
+	btd_adapter_unref(dadapter->adapter);
+	g_free(dadapter);
+}
+
+struct btd_profile deviceid_profile = {
+	.name		= "deviceid",
+	.adapter_probe	= deviceid_adapter_probe,
+	.adapter_remove	= deviceid_adapter_remove,
+};
+
+static int deviceid_init(void)
+{
+	if (main_opts.did_source == 0) {
+		info("Device ID information disabled");
+		return -1;
+	}
+
+	return btd_profile_register(&deviceid_profile);
+}
+
+static void deviceid_exit(void)
+{
+	btd_profile_unregister(&deviceid_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceid, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			deviceid_init, deviceid_exit)
diff --git a/src/adapter.c b/src/adapter.c
index b99bff9..ed4824c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3929,17 +3929,12 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
 	adapter->system_name = g_strdup(main_opts.name);
 	adapter->major_class = (main_opts.class & 0x001f00) >> 8;
 	adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
-	adapter->modalias = bt_modalias(main_opts.did_source,
-						main_opts.did_vendor,
-						main_opts.did_product,
-						main_opts.did_version);
 	adapter->discoverable_timeout = main_opts.discovto;
 	adapter->pairable_timeout = main_opts.pairto;
 
 	DBG("System name: %s", adapter->system_name);
 	DBG("Major class: %u", adapter->major_class);
 	DBG("Minor class: %u", adapter->minor_class);
-	DBG("Modalias: %s", adapter->modalias);
 	DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
 	DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
 
@@ -5566,14 +5561,23 @@ void adapter_foreach(adapter_cb func, gpointer user_data)
 	g_slist_foreach(adapters, (GFunc) func, user_data);
 }
 
-static int set_did(struct btd_adapter *adapter, uint16_t vendor,
-			uint16_t product, uint16_t version, uint16_t source)
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
 {
 	struct mgmt_cp_set_device_id cp;
 
 	DBG("hci%u source %x vendor %x product %x version %x",
 			adapter->dev_id, source, vendor, product, version);
 
+	g_free(adapter->modalias);
+	adapter->modalias = bt_modalias(source, vendor, product, version);
+
+	DBG("Modalias: %s", adapter->modalias);
+
+	g_dbus_emit_property_changed(dbus_conn, adapter->path,
+						ADAPTER_INTERFACE, "Modalias");
+
 	memset(&cp, 0, sizeof(cp));
 
 	cp.source = htobs(source);
@@ -5638,14 +5642,6 @@ static int adapter_register(struct btd_adapter *adapter)
 
 	adapter->initialized = TRUE;
 
-	if (main_opts.did_source) {
-		/* DeviceID record is added by sdpd-server before any other
-		 * record is registered. */
-		adapter_service_insert(adapter, sdp_record_find(0x10000));
-		set_did(adapter, main_opts.did_vendor, main_opts.did_product,
-				main_opts.did_version, main_opts.did_source);
-	}
-
 	DBG("Adapter %s registered", adapter->path);
 
 	return 0;
diff --git a/src/adapter.h b/src/adapter.h
index 5d124e7..a6fb340 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -113,6 +113,9 @@ void btd_adapter_unref(struct btd_adapter *adapter);
 
 void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 							uint8_t minor);
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version);
 
 struct btd_adapter_driver {
 	const char *name;
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index 7b1351f..de5aef1 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -238,10 +238,6 @@ int start_sdp_server(uint16_t mtu, uint32_t flags)
 		return -1;
 	}
 
-	if (main_opts.did_source > 0)
-		register_device_id(main_opts.did_source, main_opts.did_vendor,
-				main_opts.did_product, main_opts.did_version);
-
 	io = g_io_channel_unix_new(l2cap_sock);
 	g_io_channel_set_close_on_unref(io, TRUE);
 
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 09f6c0a..2da70b5 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -176,64 +176,6 @@ void register_server_service(void)
 	update_db_timestamp();
 }
 
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version)
-{
-	const uint16_t spec = 0x0103;
-	const uint8_t primary = 1;
-	sdp_list_t *class_list, *group_list, *profile_list;
-	uuid_t class_uuid, group_uuid;
-	sdp_data_t *sdp_data, *primary_data, *source_data;
-	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record = sdp_record_alloc();
-
-	DBG("Adding device id record for %04x:%04x:%04x:%04x",
-					source, vendor, product, version);
-
-	record->handle = sdp_next_handle();
-
-	sdp_record_add(BDADDR_ANY, record);
-	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
-	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
-
-	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
-	class_list = sdp_list_append(0, &class_uuid);
-	sdp_set_service_classes(record, class_list);
-	sdp_list_free(class_list, NULL);
-
-	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
-	group_list = sdp_list_append(NULL, &group_uuid);
-	sdp_set_browse_groups(record, group_list);
-	sdp_list_free(group_list, NULL);
-
-	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
-	profile.version = spec;
-	profile_list = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, profile_list);
-	sdp_list_free(profile_list, NULL);
-
-	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
-	sdp_attr_add(record, 0x0200, spec_data);
-
-	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
-	sdp_attr_add(record, 0x0201, vendor_data);
-
-	product_data = sdp_data_alloc(SDP_UINT16, &product);
-	sdp_attr_add(record, 0x0202, product_data);
-
-	version_data = sdp_data_alloc(SDP_UINT16, &version);
-	sdp_attr_add(record, 0x0203, version_data);
-
-	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
-	sdp_attr_add(record, 0x0204, primary_data);
-
-	source_data = sdp_data_alloc(SDP_UINT16, &source);
-	sdp_attr_add(record, 0x0205, source_data);
-
-	update_db_timestamp();
-}
-
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 {
 	sdp_data_t *data;
diff --git a/src/sdpd.h b/src/sdpd.h
index 3c6ee01..174a4d7 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -54,8 +54,6 @@ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
 
 void register_public_browse_group(void);
 void register_server_service(void);
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v2 7/8] sdptool: Remove support for adding and removing service records
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

SDP database should now be controlled only by adapters. SDP code
is no longer able to notify controllers about external changes to
database. This results in services added/removed by sdptool being
not updated properly in adapter structure.
---
 tools/sdptool.1 |   16 -
 tools/sdptool.c | 2595 ++-----------------------------------------------------
 2 files changed, 54 insertions(+), 2557 deletions(-)

diff --git a/tools/sdptool.1 b/tools/sdptool.1
index 88ad818..ee95e67 100644
--- a/tools/sdptool.1
+++ b/tools/sdptool.1
@@ -82,18 +82,6 @@ Browse all available services on the device
 specified by a Bluetooth address as a parameter.
 .IP "\fBrecords [--tree] [--raw] [--xml] bdaddr\fP" 10
 Retrieve all possible service records.
-.IP "\fBadd [ --handle=N --channel=N ]\fP" 10
-Add a service to the local
-SDP database.
-.IP "" 10
-You can specify a handle for this record using
-the \fB--handle\fP option.
-.IP "" 10
-You can specify a channel to add the service on
-using the \fB--channel\fP option.
-.IP "\fBdel record_handle\fP" 10
-Remove a service from the local
-SDP database.
 .IP "\fBget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\fP" 10
 Retrieve a service from the local
 SDP database.
@@ -112,10 +100,6 @@ Displays help on using sdptool.
 sdptool browse 00:80:98:24:15:6D
 .PP
 sdptool browse local
-.PP
-sdptool add DUN
-.PP
-sdptool del 0x10000
 .SH "BUGS"
 .PP
 Documentation needs improving.
diff --git a/tools/sdptool.c b/tools/sdptool.c
index c241655..7d1121d 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -1145,2148 +1145,30 @@ static void print_service_attr(sdp_record_t *rec)
 	}
 }
 
-/*
- * Support for Service (de)registration
- */
-typedef struct {
-	uint32_t handle;
-	char *name;
-	char *provider;
-	char *desc;
-	unsigned int class;
-	unsigned int profile;
-	uint16_t psm;
-	uint8_t channel;
-	uint8_t network;
-} svc_info_t;
-
-static int add_sp(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
-	uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
-	sdp_profile_desc_t profile;
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 1;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-	sdp_list_free(root, 0);
-
-	sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &sp_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-	sdp_list_free(svclass_id, 0);
-
-	sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
-	profile.version = 0x0100;
-	profiles = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, profiles);
-	sdp_list_free(profiles, 0);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_add_lang_attr(&record);
-
-	sdp_set_info_attr(&record, "Serial Port", "BlueZ", "COM Port");
-
-	sdp_set_url_attr(&record, "http://www.bluez.org/",
-			"http://www.bluez.org/", "http://www.bluez.org/");
-
-	sdp_set_service_id(&record, sp_uuid);
-	sdp_set_service_ttl(&record, 0xffff);
-	sdp_set_service_avail(&record, 0xff);
-	sdp_set_record_state(&record, 0x00001234);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Serial Port service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_dun(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
-	uuid_t rootu, dun, gn, l2cap, rfcomm;
-	sdp_profile_desc_t profile;
-	sdp_list_t *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 2;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&rootu, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &rootu);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &dun);
-	sdp_uuid16_create(&gn,  GENERIC_NETWORKING_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &gn);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Dial-Up Networking", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Dial-Up Networking service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_fax(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, fax_uuid, tel_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel? si->channel : 3;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&fax_uuid, FAX_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &fax_uuid);
-	sdp_uuid16_create(&tel_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &tel_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, FAX_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq  = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Fax", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-	printf("Fax service registered\n");
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-	return ret;
-}
-
-static int add_lan(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 4;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, LAN_ACCESS_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, LAN_ACCESS_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "LAN Access over PPP", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("LAN Access service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_headset(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 5;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Headset", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Headset service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_headset_ag(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 7;
-	sdp_data_t *channel;
-	uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
-	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
-
-	sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
-	if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Headset AG service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_handsfree(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 6;
-	uint16_t u16 = 0x31;
-	sdp_data_t *channel, *features;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-	profile.version = 0x0101;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	features = sdp_data_alloc(SDP_UINT16, &u16);
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Handsfree", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Handsfree service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_handsfree_ag(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel : 7;
-	uint16_t u16 = 0x17;
-	sdp_data_t *channel, *features;
-	uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
-	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-	profile.version = 0x0105;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	features = sdp_data_alloc(SDP_UINT16, &u16);
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
-
-	sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
-	if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Handsfree AG service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_simaccess(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t u8 = si->channel? si->channel : 8;
-	uint16_t u16 = 0x31;
-	sdp_data_t *channel, *features;
-	int ret = 0;
-
-	memset((void *)&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, SAP_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
-	profile.version = 0x0101;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	features = sdp_data_alloc(SDP_UINT16, &u16);
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "SIM Access", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("SIM Access service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_opush(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_record_t record;
-	uint8_t chan = si->channel ? si->channel : 9;
-	sdp_data_t *channel;
-	uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
-	void *dtds[sizeof(formats)], *values[sizeof(formats)];
-	unsigned int i;
-	uint8_t dtd = SDP_UINT8;
-	sdp_data_t *sflist;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &opush_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &chan);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(0, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	for (i = 0; i < sizeof(formats); i++) {
-		dtds[i] = &dtd;
-		values[i] = &formats[i];
-	}
-	sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
-
-	sdp_set_info_attr(&record, "OBEX Object Push", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("OBEX Object Push service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(proto[2], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_pbap(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, pbap_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_record_t record;
-	uint8_t chan = si->channel ? si->channel : 19;
-	sdp_data_t *channel;
-	uint8_t formats[] = {0x01};
-	uint8_t dtd = SDP_UINT8;
-	sdp_data_t *sflist;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&pbap_uuid, PBAP_PSE_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &pbap_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &chan);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(0, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sflist = sdp_data_alloc(dtd,formats);
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
-
-	sdp_set_info_attr(&record, "OBEX Phonebook Access Server", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record,
-			SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("PBAP service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(proto[2], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_ftp(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_record_t record;
-	uint8_t u8 = si->channel ? si->channel: 10;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &ftrn_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &u8);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(0, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "OBEX File Transfer", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("OBEX File Transfer service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(proto[2], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_directprint(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_record_t record;
-	uint8_t chan = si->channel ? si->channel : 12;
-	sdp_data_t *channel;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&opush_uuid, DIRECT_PRINTING_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &opush_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, BASIC_PRINTING_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &chan);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(0, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Direct Printing", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("Direct Printing service registered\n");
-
-end:
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(proto[2], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_nap(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint16_t lp = 0x000f, ver = 0x0100;
-	sdp_data_t *psm, *version;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&ftrn_uuid, NAP_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &ftrn_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
-	proto[1] = sdp_list_append(0, &bnep_uuid);
-	version  = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-
-	{
-		uint16_t ptype[4] = { 0x0010, 0x0020, 0x0030, 0x0040 };
-		sdp_data_t *head, *pseq;
-		int p;
-
-		for (p = 0, head = NULL; p < 4; p++) {
-			sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
-			head = sdp_seq_append(head, data);
-		}
-		pseq = sdp_data_alloc(SDP_SEQ16, head);
-		proto[1] = sdp_list_append(proto[1], pseq);
-	}
-
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Network Access Point Service", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("NAP service registered\n");
-
-end:
-	sdp_data_free(version);
-	sdp_data_free(psm);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_gn(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint16_t lp = 0x000f, ver = 0x0100;
-	sdp_data_t *psm, *version;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&ftrn_uuid, GN_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &ftrn_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
-	proto[1] = sdp_list_append(0, &bnep_uuid);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Group Network Service", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("GN service registered\n");
-
-end:
-	sdp_data_free(version);
-	sdp_data_free(psm);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_panu(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint16_t lp = 0x000f, ver = 0x0100;
-	sdp_data_t *psm, *version;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-	sdp_list_free(root, NULL);
-
-	sdp_uuid16_create(&ftrn_uuid, PANU_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &ftrn_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-	sdp_list_free(svclass_id, NULL);
-
-	sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(NULL, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-	sdp_list_free(pfseq, NULL);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(NULL, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(NULL, proto[0]);
-
-	sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
-	proto[1] = sdp_list_append(NULL, &bnep_uuid);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "PAN User", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("PANU service registered\n");
-
-end:
-	sdp_data_free(version);
-	sdp_data_free(psm);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
-	unsigned int i;
-	uint8_t dtd = SDP_UINT16;
-	uint8_t dtd2 = SDP_UINT8;
-	uint8_t dtd_data = SDP_TEXT_STR8;
-	void *dtds[2];
-	void *values[2];
-	void *dtds2[2];
-	void *values2[2];
-	int leng[2];
-	uint8_t hid_spec_type = 0x22;
-	uint16_t hid_attr_lang[] = { 0x409, 0x100 };
-	static const uint16_t ctrl = 0x11;
-	static const uint16_t intr = 0x13;
-	static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
-	static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
-	const uint8_t hid_spec[] = {
-		0x05, 0x01, // usage page
-		0x09, 0x06, // keyboard
-		0xa1, 0x01, // key codes
-		0x85, 0x01, // minimum
-		0x05, 0x07, // max
-		0x19, 0xe0, // logical min
-		0x29, 0xe7, // logical max
-		0x15, 0x00, // report size
-		0x25, 0x01, // report count
-		0x75, 0x01, // input data variable absolute
-		0x95, 0x08, // report count
-		0x81, 0x02, // report size
-		0x75, 0x08,
-		0x95, 0x01,
-		0x81, 0x01,
-		0x75, 0x01,
-		0x95, 0x05,
-		0x05, 0x08,
-		0x19, 0x01,
-		0x29, 0x05,
-		0x91, 0x02,
-		0x75, 0x03,
-		0x95, 0x01,
-		0x91, 0x01,
-		0x75, 0x08,
-		0x95, 0x06,
-		0x15, 0x00,
-		0x26, 0xff,
-		0x00, 0x05,
-		0x07, 0x19,
-		0x00, 0x2a,
-		0xff, 0x00,
-		0x81, 0x00,
-		0x75, 0x01,
-		0x95, 0x01,
-		0x15, 0x00,
-		0x25, 0x01,
-		0x05, 0x0c,
-		0x09, 0xb8,
-		0x81, 0x06,
-		0x09, 0xe2,
-		0x81, 0x06,
-		0x09, 0xe9,
-		0x81, 0x02,
-		0x09, 0xea,
-		0x81, 0x02,
-		0x75, 0x01,
-		0x95, 0x04,
-		0x81, 0x01,
-		0xc0         // end tag
-	};
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_add_lang_attr(&record);
-
-	sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &hidkb_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	/* protocols */
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[1] = sdp_list_append(0, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &ctrl);
-	proto[1] = sdp_list_append(proto[1], psm);
-	apseq = sdp_list_append(0, proto[1]);
-
-	sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
-	proto[2] = sdp_list_append(0, &hidp_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	/* additional protocols */
-	proto[1] = sdp_list_append(0, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &intr);
-	proto[1] = sdp_list_append(proto[1], psm);
-	apseq = sdp_list_append(0, proto[1]);
-
-	sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
-	proto[2] = sdp_list_append(0, &hidp_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_add_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "HID Keyboard", NULL, NULL);
-
-	for (i = 0; i < sizeof(hid_attr) / 2; i++)
-		sdp_attr_add_new(&record,
-					SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
-					SDP_UINT16, &hid_attr[i]);
-
-	dtds[0] = &dtd2;
-	values[0] = &hid_spec_type;
-	dtds[1] = &dtd_data;
-	values[1] = (uint8_t *) hid_spec;
-	leng[0] = 0;
-	leng[1] = sizeof(hid_spec);
-	hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
-	hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
-	sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
-
-	for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
-		dtds2[i] = &dtd;
-		values2[i] = &hid_attr_lang[i];
-	}
-
-	lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
-	lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
-	sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
-
-	for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
-		sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
-						SDP_UINT16, &hid_attr2[i + 1]);
-
-	if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("HID keyboard service registered\n");
-
-	return 0;
-}
-
-static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
-	unsigned int i;
-	uint8_t dtd = SDP_UINT16;
-	uint8_t dtd2 = SDP_UINT8;
-	uint8_t dtd_data = SDP_TEXT_STR8;
-	void *dtds[2];
-	void *values[2];
-	void *dtds2[2];
-	void *values2[2];
-	int leng[2];
-	uint8_t hid_spec_type = 0x22;
-	uint16_t hid_attr_lang[] = { 0x409, 0x100 };
-	uint16_t ctrl = 0x11, intr = 0x13;
-	uint16_t hid_release = 0x0100, parser_version = 0x0111;
-	uint8_t subclass = 0x04, country = 0x33;
-	uint8_t virtual_cable = 0, reconnect = 1, sdp_disable = 0;
-	uint8_t battery = 1, remote_wakeup = 1;
-	uint16_t profile_version = 0x0100, superv_timeout = 0x0c80;
-	uint8_t norm_connect = 0, boot_device = 0;
-	const uint8_t hid_spec[] = {
-		0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
-		0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
-		0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
-		0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
-		0xc0, 0x00
-	};
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &hid_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(NULL, profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[1] = sdp_list_append(0, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &ctrl);
-	proto[1] = sdp_list_append(proto[1], psm);
-	apseq = sdp_list_append(0, proto[1]);
-
-	sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
-	proto[2] = sdp_list_append(0, &hidp_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	proto[1] = sdp_list_append(0, &l2cap_uuid);
-	psm = sdp_data_alloc(SDP_UINT16, &intr);
-	proto[1] = sdp_list_append(proto[1], psm);
-	apseq = sdp_list_append(0, proto[1]);
-
-	sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
-	proto[2] = sdp_list_append(0, &hidp_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_add_access_protos(&record, aproto);
-
-	sdp_add_lang_attr(&record);
-
-	sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
-					"Nintendo", "Nintendo RVL-CNT-01");
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
-						SDP_UINT16, &hid_release);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION,
-						SDP_UINT16, &parser_version);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS,
-						SDP_UINT8, &subclass);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE,
-						SDP_UINT8, &country);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE,
-						SDP_BOOL, &virtual_cable);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE,
-						SDP_BOOL, &reconnect);
-
-	dtds[0] = &dtd2;
-	values[0] = &hid_spec_type;
-	dtds[1] = &dtd_data;
-	values[1] = (uint8_t *) hid_spec;
-	leng[0] = 0;
-	leng[1] = sizeof(hid_spec);
-	hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
-	hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
-	sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
-
-	for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
-		dtds2[i] = &dtd;
-		values2[i] = &hid_attr_lang[i];
-	}
-
-	lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
-	lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
-	sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE,
-						SDP_BOOL, &sdp_disable);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_BATTERY_POWER,
-						SDP_BOOL, &battery);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP,
-						SDP_BOOL, &remote_wakeup);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_PROFILE_VERSION,
-						SDP_UINT16, &profile_version);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_SUPERVISION_TIMEOUT,
-						SDP_UINT16, &superv_timeout);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_NORMALLY_CONNECTABLE,
-						SDP_BOOL, &norm_connect);
-
-	sdp_attr_add_new(&record, SDP_ATTR_HID_BOOT_DEVICE,
-						SDP_BOOL, &boot_device);
-
-	if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("Wii-Mote service registered\n");
-
-	return 0;
-}
-
-static int add_cip(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, l2cap, cmtp, cip;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint16_t psm = si->psm ? si->psm : 0x1001;
-	uint8_t netid = si->network ? si->network : 0x02; // 0x02 = ISDN, 0x03 = GSM
-	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&cip, CIP_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &cip);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, CIP_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	apseq = sdp_list_append(0, proto[0]);
-	proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
-	apseq = sdp_list_append(apseq, proto[0]);
-
-	sdp_uuid16_create(&cmtp, CMTP_UUID);
-	proto[1] = sdp_list_append(0, &cmtp);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
-	sdp_set_info_attr(&record, "Common ISDN Access", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("CIP service registered\n");
-
-end:
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_data_free(network);
-
-	return ret;
-}
-
-static int add_ctp(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, l2cap, tcsbin, ctp;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	uint8_t netid = si->network ? si->network : 0x02; // 0x01-0x07 cf. p120 profile document
-	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&ctp, CORDLESS_TELEPHONY_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &ctp);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, CORDLESS_TELEPHONY_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&tcsbin, TCS_BIN_UUID);
-	proto[1] = sdp_list_append(0, &tcsbin);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
-	sdp_set_info_attr(&record, "Cordless Telephony", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto end;
-	}
-
-	printf("CTP service registered\n");
-
-end:
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_data_free(network);
-
-	return ret;
-}
-
-static int add_a2source(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, l2cap, avdtp, a2src;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	sdp_data_t *psm, *version;
-	uint16_t lp = 0x0019, ver = 0x0100;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &a2src);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&avdtp, AVDTP_UUID);
-	proto[1] = sdp_list_append(0, &avdtp);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Audio Source", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto done;
-	}
-
-	printf("Audio source service registered\n");
-
-done:
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_a2sink(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, l2cap, avdtp, a2snk;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	sdp_data_t *psm, *version;
-	uint16_t lp = 0x0019, ver = 0x0100;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&a2snk, AUDIO_SINK_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &a2snk);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&avdtp, AVDTP_UUID);
-	proto[1] = sdp_list_append(0, &avdtp);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Audio Sink", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto done;
-	}
-
-	printf("Audio sink service registered\n");
-
-done:
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_avrct(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, l2cap, avctp, avrct;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	sdp_data_t *psm, *version, *features;
-	uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &avrct);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&avctp, AVCTP_UUID);
-	proto[1] = sdp_list_append(0, &avctp);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	features = sdp_data_alloc(SDP_UINT16, &feat);
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-	sdp_set_info_attr(&record, "AVRCP CT", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto done;
-	}
-
-	printf("Remote control service registered\n");
-
-done:
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_avrtg(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, l2cap, avctp, avrtg;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	sdp_data_t *psm, *version, *features;
-	uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
-	int ret = 0;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &avrtg);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(0, &profile[0]);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap);
-	psm = sdp_data_alloc(SDP_UINT16, &lp);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&avctp, AVCTP_UUID);
-	proto[1] = sdp_list_append(0, &avctp);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
-	proto[1] = sdp_list_append(proto[1], version);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	features = sdp_data_alloc(SDP_UINT16, &feat);
-	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-	sdp_set_info_attr(&record, "AVRCP TG", 0, 0);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		ret = -1;
-		goto done;
-	}
-
-	printf("Remote target service registered\n");
-
-done:
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(aproto, 0);
-
-	return ret;
-}
-
-static int add_udi_ue(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	uint8_t channel = si->channel ? si->channel: 18;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-	sdp_list_free(root, NULL);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-		sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid16_create(&svclass_uuid, UDI_MT_SVCLASS_ID);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-	sdp_list_free(svclass, NULL);
-
-	sdp_set_info_attr(&record, "UDI UE", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("UDI UE service registered\n");
-
-	return 0;
-}
-
-static int add_udi_te(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	uint8_t channel = si->channel ? si->channel: 19;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-	sdp_list_free(root, NULL);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-		sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid16_create(&svclass_uuid, UDI_TA_SVCLASS_ID);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-	sdp_list_free(svclass, NULL);
-
-	sdp_set_info_attr(&record, "UDI TE", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("UDI TE service registered\n");
-
-	return 0;
-}
-
 static unsigned char sr1_uuid[] = {	0xbc, 0x19, 0x9c, 0x24, 0x95, 0x8b, 0x4c, 0xc0,
 					0xa2, 0xcb, 0xfd, 0x8a, 0x30, 0xbf, 0x32, 0x06 };
 
-static int add_sr1(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass;
-	uuid_t root_uuid, svclass_uuid;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid128_create(&svclass_uuid, (void *) sr1_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_set_info_attr(&record, "TOSHIBA SR-1", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("Toshiba Speech Recognition SR-1 service record registered\n");
-
-	return 0;
-}
-
 static unsigned char syncmls_uuid[] = {	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
 					0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
 
 static unsigned char syncmlc_uuid[] = {	0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
 					0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
 
-static int add_syncml(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	uint8_t channel = si->channel ? si->channel: 15;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid128_create(&svclass_uuid, (void *) syncmlc_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-		sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(NULL, &obex_uuid));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_set_info_attr(&record, "SyncML Client", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("SyncML Client service record registered\n");
-
-	return 0;
-}
-
 static unsigned char async_uuid[] = {	0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
 					0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
 
-static int add_activesync(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	uint8_t channel = si->channel ? si->channel: 21;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-	sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid128_create(&svclass_uuid, (void *) async_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_set_info_attr(&record, "Microsoft ActiveSync", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("ActiveSync service record registered\n");
-
-	return 0;
-}
-
 static unsigned char hotsync_uuid[] = {	0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5,
 					0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C };
 
-static int add_hotsync(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	uint8_t channel = si->channel ? si->channel: 22;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-	sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("HotSync service record registered\n");
-
-	return 0;
-}
-
 static unsigned char palmos_uuid[] = {	0xF5, 0xBE, 0xB6, 0x51, 0x41, 0x71, 0x40, 0x51,
 					0xAC, 0xF5, 0x6C, 0xA7, 0x20, 0x22, 0x42, 0xF0 };
 
-static int add_palmos(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass;
-	uuid_t root_uuid, svclass_uuid;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid128_create(&svclass_uuid, (void *) palmos_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("PalmOS service record registered\n");
-
-	return 0;
-}
-
 static unsigned char nokid_uuid[] = {	0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00,
 					0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
 
-static int add_nokiaid(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass;
-	uuid_t root_uuid, svclass_uuid;
-	uint16_t verid = 0x005f;
-	sdp_data_t *version = sdp_data_alloc(SDP_UINT16, &verid);
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid128_create(&svclass_uuid, (void *) nokid_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_attr_add(&record, SDP_ATTR_SERVICE_VERSION, version);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		sdp_data_free(version);
-		return -1;
-	}
-
-	printf("Nokia ID service record registered\n");
-
-	return 0;
-}
-
 static unsigned char pcsuite_uuid[] = {	0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x10, 0x00,
 					0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
 
-static int add_pcsuite(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	uint8_t channel = si->channel ? si->channel: 14;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-		sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid128_create(&svclass_uuid, (void *) pcsuite_uuid);
-	svclass = sdp_list_append(NULL, &svclass_uuid);
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_set_info_attr(&record, "Nokia PC Suite", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("Nokia PC Suite service registered\n");
-
-	return 0;
-}
-
 static unsigned char nftp_uuid[] = {	0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x10, 0x00,
 					0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
 
@@ -3302,436 +1184,69 @@ static unsigned char apple_uuid[] = {	0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e,
 static unsigned char iap_uuid[] = {	0x00, 0x00, 0x00, 0x00, 0xde, 0xca, 0xfa, 0xde,
 					0xde, 0xca, 0xde, 0xaf, 0xde, 0xca, 0xca, 0xfe };
 
-static int add_apple(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root;
-	uuid_t root_uuid;
-	uint32_t attr783 = 0x00000000;
-	uint32_t attr785 = 0x00000002;
-	uint16_t attr786 = 0x1234;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_attr_add_new(&record, 0x0780, SDP_UUID128, (void *) apple_uuid);
-	sdp_attr_add_new(&record, 0x0781, SDP_TEXT_STR8, (void *) "Macmini");
-	sdp_attr_add_new(&record, 0x0782, SDP_TEXT_STR8, (void *) "PowerMac10,1");
-	sdp_attr_add_new(&record, 0x0783, SDP_UINT32, (void *) &attr783);
-	sdp_attr_add_new(&record, 0x0784, SDP_TEXT_STR8, (void *) "1.6.6f22");
-	sdp_attr_add_new(&record, 0x0785, SDP_UINT32, (void *) &attr785);
-	sdp_attr_add_new(&record, 0x0786, SDP_UUID16, (void *) &attr786);
-
-	sdp_set_info_attr(&record, "Apple Macintosh Attributes", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("Apple attribute service registered\n");
-
-	return 0;
-}
-
-static int add_isync(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_list_t *root, *svclass, *proto;
-	uuid_t root_uuid, svclass_uuid, serial_uuid, l2cap_uuid, rfcomm_uuid;
-	uint8_t channel = si->channel ? si->channel : 16;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto = sdp_list_append(proto, sdp_list_append(
-		sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid16_create(&serial_uuid, SERIAL_PORT_SVCLASS_ID);
-	svclass = sdp_list_append(NULL, &serial_uuid);
-
-	sdp_uuid16_create(&svclass_uuid, APPLE_AGENT_SVCLASS_ID);
-	svclass = sdp_list_append(svclass, &svclass_uuid);
-
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_set_info_attr(&record, "AppleAgent", "Bluetooth acceptor", "Apple Computer Ltd.");
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	printf("Apple iSync service registered\n");
-
-	return 0;
-}
-
-static int add_semchla(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_record_t record;
-	sdp_profile_desc_t profile;
-	sdp_list_t *root, *svclass, *proto, *profiles;
-	uuid_t root_uuid, service_uuid, l2cap_uuid, semchla_uuid;
-	uint16_t psm = 0xf0f9;
-
-	memset(&record, 0, sizeof(record));
-	record.handle = si->handle;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto = sdp_list_append(NULL, sdp_list_append(
-		sdp_list_append(NULL, &l2cap_uuid), sdp_data_alloc(SDP_UINT16, &psm)));
-
-	sdp_uuid32_create(&semchla_uuid, 0x8e770300);
-	proto = sdp_list_append(proto, sdp_list_append(NULL, &semchla_uuid));
-
-	sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
-
-	sdp_uuid32_create(&service_uuid, 0x8e771301);
-	svclass = sdp_list_append(NULL, &service_uuid);
-
-	sdp_set_service_classes(&record, svclass);
-
-	sdp_uuid32_create(&profile.uuid, 0x8e771302);	// Headset
-	//sdp_uuid32_create(&profile.uuid, 0x8e771303);	// Phone
-	profile.version = 0x0100;
-	profiles = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(&record, profiles);
-
-	sdp_set_info_attr(&record, "SEMC HLA", NULL, NULL);
-
-	if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
-		printf("Service Record registration failed\n");
-		return -1;
-	}
-
-	/* SEMC High Level Authentication */
-	printf("SEMC HLA service registered\n");
-
-	return 0;
-}
-
-static int add_gatt(sdp_session_t *session, svc_info_t *si)
-{
-	sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
-	uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
-	sdp_profile_desc_t profile;
-	sdp_record_t record;
-	sdp_data_t *psm, *sh, *eh;
-	uint16_t att_psm = 27, start = 0x0001, end = 0x000f;
-	int ret;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-	record.handle = si->handle;
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-	sdp_list_free(root, NULL);
-
-	sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &gatt_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-	sdp_list_free(svclass_id, NULL);
-
-	sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
-	profile.version = 0x0100;
-	profiles = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(&record, profiles);
-	sdp_list_free(profiles, NULL);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(NULL, &l2cap);
-	psm = sdp_data_alloc(SDP_UINT16, &att_psm);
-	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(NULL, proto[0]);
-
-	sdp_uuid16_create(&proto_uuid, ATT_UUID);
-	proto[1] = sdp_list_append(NULL, &proto_uuid);
-	sh = sdp_data_alloc(SDP_UINT16, &start);
-	proto[1] = sdp_list_append(proto[1], sh);
-	eh = sdp_data_alloc(SDP_UINT16, &end);
-	proto[1] = sdp_list_append(proto[1], eh);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Generic Attribute Profile", "BlueZ", NULL);
-
-	sdp_set_url_attr(&record, "http://www.bluez.org/",
-			"http://www.bluez.org/", "http://www.bluez.org/");
-
-	sdp_set_service_id(&record, gatt_uuid);
-
-	ret = sdp_device_record_register(session, &interface, &record,
-							SDP_RECORD_PERSIST);
-	if (ret < 0)
-		printf("Service Record registration failed\n");
-	else
-		printf("Generic Attribute Profile Service registered\n");
-
-	sdp_data_free(psm);
-	sdp_data_free(sh);
-	sdp_data_free(eh);
-	sdp_list_free(proto[0], NULL);
-	sdp_list_free(proto[1], NULL);
-	sdp_list_free(apseq, NULL);
-	sdp_list_free(aproto, NULL);
-
-	return ret;
-}
-
 struct {
 	char		*name;
 	uint32_t	class;
-	int		(*add)(sdp_session_t *sess, svc_info_t *si);
 	unsigned char *uuid;
 } service[] = {
-	{ "DID",	PNP_INFO_SVCLASS_ID,		NULL,		},
-
-	{ "SP",		SERIAL_PORT_SVCLASS_ID,		add_sp		},
-	{ "DUN",	DIALUP_NET_SVCLASS_ID,		add_dun		},
-	{ "LAN",	LAN_ACCESS_SVCLASS_ID,		add_lan		},
-	{ "FAX",	FAX_SVCLASS_ID,			add_fax		},
-	{ "OPUSH",	OBEX_OBJPUSH_SVCLASS_ID,	add_opush	},
-	{ "FTP",	OBEX_FILETRANS_SVCLASS_ID,	add_ftp		},
-	{ "PRINT",	DIRECT_PRINTING_SVCLASS_ID,	add_directprint	},
-
-	{ "HS",		HEADSET_SVCLASS_ID,		add_headset	},
-	{ "HSAG",	HEADSET_AGW_SVCLASS_ID,		add_headset_ag	},
-	{ "HF",		HANDSFREE_SVCLASS_ID,		add_handsfree	},
-	{ "HFAG",	HANDSFREE_AGW_SVCLASS_ID,	add_handsfree_ag},
-	{ "SAP",	SAP_SVCLASS_ID,			add_simaccess	},
-	{ "PBAP",	PBAP_SVCLASS_ID,		add_pbap,	},
-
-	{ "NAP",	NAP_SVCLASS_ID,			add_nap		},
-	{ "GN",		GN_SVCLASS_ID,			add_gn		},
-	{ "PANU",	PANU_SVCLASS_ID,		add_panu	},
-
-	{ "HCRP",	HCR_SVCLASS_ID,			NULL		},
-	{ "HID",	HID_SVCLASS_ID,			NULL		},
-	{ "KEYB",	HID_SVCLASS_ID,			add_hid_keyb	},
-	{ "WIIMOTE",	HID_SVCLASS_ID,			add_hid_wiimote	},
-	{ "CIP",	CIP_SVCLASS_ID,			add_cip		},
-	{ "CTP",	CORDLESS_TELEPHONY_SVCLASS_ID,	add_ctp		},
-
-	{ "A2SRC",	AUDIO_SOURCE_SVCLASS_ID,	add_a2source	},
-	{ "A2SNK",	AUDIO_SINK_SVCLASS_ID,		add_a2sink	},
-	{ "AVRCT",	AV_REMOTE_SVCLASS_ID,		add_avrct	},
-	{ "AVRTG",	AV_REMOTE_TARGET_SVCLASS_ID,	add_avrtg	},
-
-	{ "UDIUE",	UDI_MT_SVCLASS_ID,		add_udi_ue	},
-	{ "UDITE",	UDI_TA_SVCLASS_ID,		add_udi_te	},
-
-	{ "SEMCHLA",	0x8e771301,			add_semchla	},
-
-	{ "SR1",	0,				add_sr1,	sr1_uuid	},
-	{ "SYNCML",	0,				add_syncml,	syncmlc_uuid	},
-	{ "SYNCMLSERV",	0,				NULL,		syncmls_uuid	},
-	{ "ACTIVESYNC",	0,				add_activesync,	async_uuid	},
-	{ "HOTSYNC",	0,				add_hotsync,	hotsync_uuid	},
-	{ "PALMOS",	0,				add_palmos,	palmos_uuid	},
-	{ "NOKID",	0,				add_nokiaid,	nokid_uuid	},
-	{ "PCSUITE",	0,				add_pcsuite,	pcsuite_uuid	},
-	{ "NFTP",	0,				NULL,		nftp_uuid	},
-	{ "NSYNCML",	0,				NULL,		nsyncml_uuid	},
-	{ "NGAGE",	0,				NULL,		ngage_uuid	},
-	{ "APPLE",	0,				add_apple,	apple_uuid	},
-	{ "IAP",	0,				NULL,		iap_uuid	},
-
-	{ "ISYNC",	APPLE_AGENT_SVCLASS_ID,		add_isync,	},
-	{ "GATT",	GENERIC_ATTRIB_SVCLASS_ID,	add_gatt,	},
+	{ "DID",	PNP_INFO_SVCLASS_ID		},
+
+	{ "SP",		SERIAL_PORT_SVCLASS_ID		},
+	{ "DUN",	DIALUP_NET_SVCLASS_ID		},
+	{ "LAN",	LAN_ACCESS_SVCLASS_ID		},
+	{ "FAX",	FAX_SVCLASS_ID			},
+	{ "OPUSH",	OBEX_OBJPUSH_SVCLASS_ID		},
+	{ "FTP",	OBEX_FILETRANS_SVCLASS_ID	},
+	{ "PRINT",	DIRECT_PRINTING_SVCLASS_ID	},
+
+	{ "HS",		HEADSET_SVCLASS_ID		},
+	{ "HSAG",	HEADSET_AGW_SVCLASS_ID		},
+	{ "HF",		HANDSFREE_SVCLASS_ID		},
+	{ "HFAG",	HANDSFREE_AGW_SVCLASS_ID	},
+	{ "SAP",	SAP_SVCLASS_ID			},
+	{ "PBAP",	PBAP_SVCLASS_ID			},
+
+	{ "NAP",	NAP_SVCLASS_ID			},
+	{ "GN",		GN_SVCLASS_ID			},
+	{ "PANU",	PANU_SVCLASS_ID			},
+
+	{ "HCRP",	HCR_SVCLASS_ID			},
+	{ "HID",	HID_SVCLASS_ID			},
+	{ "KEYB",	HID_SVCLASS_ID			},
+	{ "WIIMOTE",	HID_SVCLASS_ID			},
+	{ "CIP",	CIP_SVCLASS_ID			},
+	{ "CTP",	CORDLESS_TELEPHONY_SVCLASS_ID	},
+
+	{ "A2SRC",	AUDIO_SOURCE_SVCLASS_ID		},
+	{ "A2SNK",	AUDIO_SINK_SVCLASS_ID		},
+	{ "AVRCT",	AV_REMOTE_SVCLASS_ID		},
+	{ "AVRTG",	AV_REMOTE_TARGET_SVCLASS_ID	},
+
+	{ "UDIUE",	UDI_MT_SVCLASS_ID		},
+	{ "UDITE",	UDI_TA_SVCLASS_ID		},
+
+	{ "SEMCHLA",	0x8e771301			},
+
+	{ "SR1",	0,				sr1_uuid	},
+	{ "SYNCML",	0,				syncmlc_uuid	},
+	{ "SYNCMLSERV",	0,				syncmls_uuid	},
+	{ "ACTIVESYNC",	0,				async_uuid	},
+	{ "HOTSYNC",	0,				hotsync_uuid	},
+	{ "PALMOS",	0,				palmos_uuid	},
+	{ "NOKID",	0,				nokid_uuid	},
+	{ "PCSUITE",	0,				pcsuite_uuid	},
+	{ "NFTP",	0,				nftp_uuid	},
+	{ "NSYNCML",	0,				nsyncml_uuid	},
+	{ "NGAGE",	0,				ngage_uuid	},
+	{ "APPLE",	0,				apple_uuid	},
+	{ "IAP",	0,				iap_uuid	},
+
+	{ "ISYNC",	APPLE_AGENT_SVCLASS_ID		},
+	{ "GATT",	GENERIC_ATTRIB_SVCLASS_ID	},
 
 	{ 0 }
 };
 
-/* Add local service */
-static int add_service(bdaddr_t *bdaddr, svc_info_t *si)
-{
-	sdp_session_t *sess;
-	int i, ret = -1;
-
-	if (!si->name)
-		return -1;
-
-	sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
-	if (!sess)
-		return -1;
-
-	for (i = 0; service[i].name; i++)
-		if (!strcasecmp(service[i].name, si->name)) {
-			if (service[i].add)
-				ret = service[i].add(sess, si);
-			goto done;
-		}
-
-	printf("Unknown service name: %s\n", si->name);
-
-done:
-	free(si->name);
-	sdp_close(sess);
-
-	return ret;
-}
-
-static struct option add_options[] = {
-	{ "help",	0, 0, 'h' },
-	{ "handle",	1, 0, 'r' },
-	{ "psm",	1, 0, 'p' },
-	{ "channel",	1, 0, 'c' },
-	{ "network",	1, 0, 'n' },
-	{ 0, 0, 0, 0 }
-};
-
-static const char *add_help =
-	"Usage:\n"
-	"\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
-
-static int cmd_add(int argc, char **argv)
-{
-	svc_info_t si;
-	int opt;
-
-	memset(&si, 0, sizeof(si));
-	si.handle = 0xffffffff;
-
-	for_each_opt(opt, add_options, 0) {
-		switch (opt) {
-		case 'r':
-			if (strncasecmp(optarg, "0x", 2))
-				si.handle = atoi(optarg);
-			else
-				si.handle = strtol(optarg + 2, NULL, 16);
-			break;
-		case 'p':
-			if (strncasecmp(optarg, "0x", 2))
-				si.psm = atoi(optarg);
-			else
-				si.psm = strtol(optarg + 2, NULL, 16);
-			break;
-		case 'c':
-			if (strncasecmp(optarg, "0x", 2))
-				si.channel = atoi(optarg);
-			else
-				si.channel = strtol(optarg + 2, NULL, 16);
-			break;
-		case 'n':
-			if (strncasecmp(optarg, "0x", 2))
-				si.network = atoi(optarg);
-			else
-				si.network = strtol(optarg + 2, NULL, 16);
-			break;
-		default:
-			printf("%s", add_help);
-			return -1;
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (argc < 1) {
-		printf("%s", add_help);
-		return -1;
-	}
-
-	si.name = strdup(argv[0]);
-
-	return add_service(0, &si);
-}
-
-/* Delete local service */
-static int del_service(bdaddr_t *bdaddr, void *arg)
-{
-	uint32_t handle, range = 0x0000ffff;
-	sdp_list_t *attr;
-	sdp_session_t *sess;
-	sdp_record_t *rec;
-
-	if (!arg) {
-		printf("Record handle was not specified.\n");
-		return -1;
-	}
-
-	sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
-	if (!sess) {
-		printf("No local SDP server!\n");
-		return -1;
-	}
-
-	handle = strtoul((char *)arg, 0, 16);
-	attr = sdp_list_append(0, &range);
-	rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr);
-	sdp_list_free(attr, 0);
-
-	if (!rec) {
-		printf("Service Record not found.\n");
-		sdp_close(sess);
-		return -1;
-	}
-
-	if (sdp_device_record_unregister(sess, &interface, rec)) {
-		printf("Failed to unregister service record: %s\n", strerror(errno));
-		sdp_close(sess);
-		return -1;
-	}
-
-	printf("Service Record deleted.\n");
-	sdp_close(sess);
-
-	return 0;
-}
-
-static struct option del_options[] = {
-	{ "help",	0, 0, 'h' },
-	{ 0, 0, 0, 0 }
-};
-
-static const char *del_help =
-	"Usage:\n"
-	"\tdel record_handle\n";
-
-static int cmd_del(int argc, char **argv)
-{
-	int opt;
-
-	for_each_opt(opt, del_options, 0) {
-		switch (opt) {
-		default:
-			printf("%s", del_help);
-			return -1;
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	if (argc < 1) {
-		printf("%s", del_help);
-		return -1;
-	}
-
-	return del_service(NULL, argv[0]);
-}
-
 /*
  * Perform an inquiry and search/browse all peer found.
  */
@@ -4203,8 +1718,6 @@ static struct {
 	{ "search",  cmd_search,      "Search for a service"          },
 	{ "browse",  cmd_browse,      "Browse all available services" },
 	{ "records", cmd_records,     "Request all records"           },
-	{ "add",     cmd_add,         "Add local service"             },
-	{ "del",     cmd_del,         "Delete local service"          },
 	{ "get",     cmd_get,         "Get local service"             },
 	{ "setattr", cmd_setattr,     "Set/Add attribute to a SDP record"          },
 	{ "setseq",  cmd_setseq,      "Set/Add attribute sequence to a SDP record" },
-- 
1.8.4


^ permalink raw reply related

* [PATCH v2 6/8] sdpd: Remove 'register' and 'remove' requests
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

sdpd is now controlled by adapters and should not be modified with
other means.
---
 src/sdpd-request.c |  14 --------
 src/sdpd-service.c | 100 -----------------------------------------------------
 src/sdpd.h         |   2 --
 3 files changed, 116 deletions(-)

diff --git a/src/sdpd-request.c b/src/sdpd-request.c
index fbeb488..5b88a10 100644
--- a/src/sdpd-request.c
+++ b/src/sdpd-request.c
@@ -997,13 +997,6 @@ static void process_request(sdp_req_t *req)
 		rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
 		break;
 	/* Following requests are allowed only for local connections */
-	case SDP_SVC_REGISTER_REQ:
-		SDPDBG("Service register request");
-		if (req->local) {
-			status = service_register_req(req, &rsp);
-			rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
-		}
-		break;
 	case SDP_SVC_UPDATE_REQ:
 		SDPDBG("Service update request");
 		if (req->local) {
@@ -1011,13 +1004,6 @@ static void process_request(sdp_req_t *req)
 			rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
 		}
 		break;
-	case SDP_SVC_REMOVE_REQ:
-		SDPDBG("Service removal request");
-		if (req->local) {
-			status = service_remove_req(req, &rsp);
-			rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
-		}
-		break;
 	default:
 		error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
 		status = SDP_INVALID_SYNTAX;
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 38bf808..09f6c0a 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -400,75 +400,6 @@ static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p,
 }
 
 /*
- * Add the newly created service record to the service repository
- */
-int service_register_req(sdp_req_t *req, sdp_buf_t *rsp)
-{
-	int scanned = 0;
-	sdp_data_t *handle;
-	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
-	int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
-	sdp_record_t *rec;
-
-	req->flags = *p++;
-	if (req->flags & SDP_DEVICE_RECORD) {
-		bacpy(&req->device, (bdaddr_t *) p);
-		p += sizeof(bdaddr_t);
-		bufsize -= sizeof(bdaddr_t);
-	}
-
-	/* save image of PDU: we need it when clients request this attribute */
-	rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned);
-	if (!rec)
-		goto invalid;
-
-	if (rec->handle == 0xffffffff) {
-		rec->handle = sdp_next_handle();
-		if (rec->handle < 0x10000) {
-			sdp_record_free(rec);
-			goto invalid;
-		}
-	} else {
-		if (sdp_record_find(rec->handle)) {
-			/* extract_pdu_server will add the record handle
-			 * if it is missing. So instead of failing, skip
-			 * the record adding to avoid duplication. */
-			goto success;
-		}
-	}
-
-	sdp_record_add(&req->device, rec);
-	if (!(req->flags & SDP_RECORD_PERSIST))
-		sdp_svcdb_set_collectable(rec, req->sock);
-
-	handle = sdp_data_alloc(SDP_UINT32, &rec->handle);
-	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle);
-
-success:
-	/* if the browse group descriptor is NULL,
-	 * ensure that the record belongs to the ROOT group */
-	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
-		uuid_t uuid;
-		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
-		sdp_pattern_add_uuid(rec, &uuid);
-	}
-
-	update_db_timestamp();
-
-	/* Build a rsp buffer */
-	bt_put_be32(rec->handle, rsp->data);
-	rsp->data_size = sizeof(uint32_t);
-
-	return 0;
-
-invalid:
-	bt_put_be16(SDP_INVALID_SYNTAX, rsp->data);
-	rsp->data_size = sizeof(uint16_t);
-
-	return -1;
-}
-
-/*
  * Update a service record
  */
 int service_update_req(sdp_req_t *req, sdp_buf_t *rsp)
@@ -509,34 +440,3 @@ done:
 	rsp->data_size = sizeof(uint16_t);
 	return status;
 }
-
-/*
- * Remove a registered service record
- */
-int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
-{
-	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
-	uint32_t handle = bt_get_be32(p);
-	sdp_record_t *rec;
-	int status = 0;
-
-	/* extract service record handle */
-
-	rec = sdp_record_find(handle);
-	if (rec) {
-		sdp_svcdb_collect(rec);
-		status = sdp_record_remove(handle);
-		sdp_record_free(rec);
-		if (status == 0)
-			update_db_timestamp();
-	} else {
-		status = SDP_INVALID_RECORD_HANDLE;
-		SDPDBG("Could not find record : 0x%x", handle);
-	}
-
-	p = rsp->data;
-	bt_put_be16(status, p);
-	rsp->data_size = sizeof(uint16_t);
-
-	return status;
-}
diff --git a/src/sdpd.h b/src/sdpd.h
index 6de0af7..3c6ee01 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -50,9 +50,7 @@ void handle_request(int sk, uint8_t *data, int len);
 
 void set_fixed_db_timestamp(uint32_t dbts);
 
-int service_register_req(sdp_req_t *req, sdp_buf_t *rsp);
 int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
-int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp);
 
 void register_public_browse_group(void);
 void register_server_service(void);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v2 5/8] unit: Remove not needed functions from test-sdp
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

SDP code no longer depends on adapter code.
---
 unit/test-sdp.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

diff --git a/unit/test-sdp.c b/unit/test-sdp.c
index 5aa6948..6d699e2 100644
--- a/unit/test-sdp.c
+++ b/unit/test-sdp.c
@@ -134,35 +134,6 @@ void btd_debug(const char *format, ...)
 {
 }
 
-struct btd_adapter;
-
-typedef void (*adapter_cb) (struct btd_adapter *adapter, gpointer user_data);
-
-void adapter_foreach(adapter_cb func, gpointer user_data);
-
-void adapter_foreach(adapter_cb func, gpointer user_data)
-{
-}
-
-struct btd_adapter *adapter_find(const bdaddr_t *sba);
-
-struct btd_adapter *adapter_find(const bdaddr_t *sba)
-{
-	return NULL;
-}
-
-void adapter_service_insert(struct btd_adapter *adapter, void *rec);
-
-void adapter_service_insert(struct btd_adapter *adapter, void *rec)
-{
-}
-
-void adapter_service_remove(struct btd_adapter *adapter, void *rec);
-
-void adapter_service_remove(struct btd_adapter *adapter, void *rec)
-{
-}
-
 static void context_quit(struct context *context)
 {
 	g_main_loop_quit(context->main_loop);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v2 4/8] Remove not needed sdp_init_services_list function
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

It is doing nothing now and can be removed.
---
 src/adapter.c       |  2 --
 src/sdpd-database.c | 21 ---------------------
 src/sdpd.h          |  2 --
 3 files changed, 25 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index fb005a6..b99bff9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5622,8 +5622,6 @@ static int adapter_register(struct btd_adapter *adapter)
 		agent_unref(agent);
 	}
 
-	sdp_init_services_list(&adapter->bdaddr);
-
 	btd_adapter_gatt_server_start(adapter);
 
 	load_config(adapter);
diff --git a/src/sdpd-database.c b/src/sdpd-database.c
index e4d4f98..f65a526 100644
--- a/src/sdpd-database.c
+++ b/src/sdpd-database.c
@@ -296,24 +296,3 @@ uint32_t sdp_next_handle(void)
 
 	return handle;
 }
-
-void sdp_init_services_list(bdaddr_t *device)
-{
-	sdp_list_t *p;
-
-	DBG("");
-
-	for (p = access_db; p != NULL; p = p->next) {
-		sdp_access_t *access = p->data;
-		sdp_record_t *rec;
-
-		if (bacmp(BDADDR_ANY, &access->device))
-			continue;
-
-		rec = sdp_record_find(access->handle);
-		if (rec == NULL)
-			continue;
-
-		SDPDBG("adding record with handle %x", access->handle);
-	}
-}
diff --git a/src/sdpd.h b/src/sdpd.h
index 9a0e1e9..6de0af7 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -81,5 +81,3 @@ void stop_sdp_server(void);
 
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
 int remove_record_from_server(uint32_t handle);
-
-void sdp_init_services_list(bdaddr_t *device);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v2 3/8] adapter: Handle removing of SDP records
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

Make adapter in charge of updating SDP database. This allow to decouple
SDP of code used for notifying adapters about SDP database change.
---
 plugins/gatt-example.c     |  2 +-
 profiles/audio/a2dp.c      | 11 +++++++----
 profiles/audio/avrcp.c     |  4 ++--
 profiles/health/hdp.c      |  2 +-
 profiles/health/hdp_util.c |  3 ++-
 profiles/network/server.c  |  4 ++--
 profiles/sap/server.c      |  2 +-
 src/adapter.c              | 13 ++++++++-----
 src/adapter.h              |  2 +-
 src/attrib-server.c        |  9 +++++----
 src/attrib-server.h        |  2 +-
 src/profile.c              |  2 +-
 src/sdpd-database.c        |  8 --------
 13 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
index b926947..9b4187a 100644
--- a/plugins/gatt-example.c
+++ b/plugins/gatt-example.c
@@ -72,7 +72,7 @@ static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
 	while (gadapter->sdp_handles != NULL) {
 		uint32_t handle = GPOINTER_TO_UINT(gadapter->sdp_handles->data);
 
-		attrib_free_sdp(handle);
+		attrib_free_sdp(gadapter->adapter, handle);
 		gadapter->sdp_handles = g_slist_remove(gadapter->sdp_handles,
 						gadapter->sdp_handles->data);
 	}
diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index d96a8b5..8477b5d 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -1326,7 +1326,8 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
 			return;
 		server->sources = g_slist_remove(server->sources, sep);
 		if (server->sources == NULL && server->source_record_id) {
-			remove_record_from_server(server->source_record_id);
+			adapter_service_remove(server->adapter,
+						server->source_record_id);
 			server->source_record_id = 0;
 		}
 	} else {
@@ -1334,7 +1335,8 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
 			return;
 		server->sinks = g_slist_remove(server->sinks, sep);
 		if (server->sinks == NULL && server->sink_record_id) {
-			remove_record_from_server(server->sink_record_id);
+			adapter_service_remove(server->adapter,
+						server->sink_record_id);
 			server->sink_record_id = 0;
 		}
 	}
@@ -1943,7 +1945,8 @@ static void a2dp_source_server_remove(struct btd_profile *p,
 					(GDestroyNotify) a2dp_unregister_sep);
 
 	if (server->source_record_id) {
-		remove_record_from_server(server->source_record_id);
+		adapter_service_remove(server->adapter,
+					server->source_record_id);
 		server->source_record_id = 0;
 	}
 
@@ -1988,7 +1991,7 @@ static void a2dp_sink_server_remove(struct btd_profile *p,
 	g_slist_free_full(server->sinks, (GDestroyNotify) a2dp_unregister_sep);
 
 	if (server->sink_record_id) {
-		remove_record_from_server(server->sink_record_id);
+		adapter_service_remove(server->adapter, server->sink_record_id);
 		server->sink_record_id = 0;
 	}
 
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index e75e804..b1b2ae6 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -3797,7 +3797,7 @@ static void avrcp_target_server_remove(struct btd_profile *p,
 		return;
 
 	if (server->tg_record_id != 0) {
-		remove_record_from_server(server->tg_record_id);
+		adapter_service_remove(adapter, server->tg_record_id);
 		server->tg_record_id = 0;
 	}
 
@@ -3880,7 +3880,7 @@ static void avrcp_controller_server_remove(struct btd_profile *p,
 		return;
 
 	if (server->ct_record_id != 0) {
-		remove_record_from_server(server->ct_record_id);
+		adapter_service_remove(adapter, server->ct_record_id);
 		server->ct_record_id = 0;
 	}
 
diff --git a/profiles/health/hdp.c b/profiles/health/hdp.c
index 7f24756..7b4e799 100644
--- a/profiles/health/hdp.c
+++ b/profiles/health/hdp.c
@@ -1403,7 +1403,7 @@ void hdp_adapter_unregister(struct btd_adapter *adapter)
 	hdp_adapter = l->data;
 	adapters = g_slist_remove(adapters, hdp_adapter);
 	if (hdp_adapter->sdp_handler > 0)
-		remove_record_from_server(hdp_adapter->sdp_handler);
+		adapter_service_remove(adapter, hdp_adapter->sdp_handler);
 	release_adapter_instance(hdp_adapter);
 	btd_adapter_unref(hdp_adapter->btd_adapter);
 	g_free(hdp_adapter);
diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c
index 7748a90..34e4671 100644
--- a/profiles/health/hdp_util.c
+++ b/profiles/health/hdp_util.c
@@ -693,7 +693,8 @@ gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
 	sdp_record_t *sdp_record;
 
 	if (adapter->sdp_handler > 0)
-		remove_record_from_server(adapter->sdp_handler);
+		adapter_service_remove(adapter->btd_adapter,
+					adapter->sdp_handler);
 
 	if (app_list == NULL) {
 		adapter->sdp_handler = 0;
diff --git a/profiles/network/server.c b/profiles/network/server.c
index d537531..7b784e5 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
@@ -628,7 +628,7 @@ static void server_disconnect(DBusConnection *conn, void *user_data)
 	ns->watch_id = 0;
 
 	if (ns->record_id) {
-		remove_record_from_server(ns->record_id);
+		adapter_service_remove(ns->na->adapter, ns->record_id);
 		ns->record_id = 0;
 	}
 
@@ -722,7 +722,7 @@ static void server_free(void *data)
 	server_remove_sessions(ns);
 
 	if (ns->record_id)
-		remove_record_from_server(ns->record_id);
+		adapter_service_remove(ns->na->adapter, ns->record_id);
 
 	g_dbus_remove_watch(btd_get_dbus_connection(), ns->watch_id);
 	g_free(ns->name);
diff --git a/profiles/sap/server.c b/profiles/sap/server.c
index 089bc7a..63314a7 100644
--- a/profiles/sap/server.c
+++ b/profiles/sap/server.c
@@ -1320,7 +1320,7 @@ static void server_remove(struct sap_server *server)
 
 	sap_server_remove_conn(server);
 
-	remove_record_from_server(server->record_id);
+	adapter_service_remove(server->adapter, server->record_id);
 
 	if (server->listen_io) {
 		g_io_channel_shutdown(server->listen_io, TRUE, NULL);
diff --git a/src/adapter.c b/src/adapter.c
index 678bc5d..fb005a6 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -986,18 +986,21 @@ int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec)
 	return 0;
 }
 
-void adapter_service_remove(struct btd_adapter *adapter, void *r)
+void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle)
 {
-	sdp_record_t *rec = r;
+	sdp_record_t *rec = sdp_record_find(handle);
 
 	DBG("%s", adapter->path);
 
+	if (!rec)
+		return;
+
 	adapter->services = sdp_list_remove(adapter->services, rec);
 
-	if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp))
-		return;
+	if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
+		remove_uuid(adapter, &rec->svclass);
 
-	remove_uuid(adapter, &rec->svclass);
+	remove_record_from_server(rec->handle);
 }
 
 static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
diff --git a/src/adapter.h b/src/adapter.h
index ef6d4ed..5d124e7 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -104,7 +104,7 @@ const bdaddr_t *adapter_get_address(struct btd_adapter *adapter);
 int adapter_set_name(struct btd_adapter *adapter, const char *name);
 
 int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec);
-void adapter_service_remove(struct btd_adapter *adapter, void *rec);
+void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle);
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter);
 
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5a76d2e..2861a00 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -139,10 +139,11 @@ static void gatt_server_free(struct gatt_server *server)
 	g_slist_free_full(server->clients, (GDestroyNotify) channel_free);
 
 	if (server->gatt_sdp_handle > 0)
-		remove_record_from_server(server->gatt_sdp_handle);
+		adapter_service_remove(server->adapter,
+					server->gatt_sdp_handle);
 
 	if (server->gap_sdp_handle > 0)
-		remove_record_from_server(server->gap_sdp_handle);
+		adapter_service_remove(server->adapter, server->gap_sdp_handle);
 
 	if (server->adapter != NULL)
 		btd_adapter_unref(server->adapter);
@@ -1377,9 +1378,9 @@ uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
 	return attrib_create_sdp_new(l->data, handle, name);
 }
 
-void attrib_free_sdp(uint32_t sdp_handle)
+void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle)
 {
-	remove_record_from_server(sdp_handle);
+	adapter_service_remove(adapter, sdp_handle);
 }
 
 static uint16_t find_uuid16_avail(struct btd_adapter *adapter, uint16_t nitems)
diff --git a/src/attrib-server.h b/src/attrib-server.h
index 2148017..90ba17c 100644
--- a/src/attrib-server.h
+++ b/src/attrib-server.h
@@ -36,6 +36,6 @@ int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
 					const uint8_t *value, size_t len);
 uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
 							const char *name);
-void attrib_free_sdp(uint32_t sdp_handle);
+void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle);
 guint attrib_channel_attach(GAttrib *attrib);
 gboolean attrib_channel_detach(GAttrib *attrib, guint id);
diff --git a/src/profile.c b/src/profile.c
index f2c1e6f..accd007 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -1371,7 +1371,7 @@ static void ext_remove_records(struct ext_profile *ext,
 
 		ext->records = g_slist_remove(ext->records, r);
 
-		remove_record_from_server(r->handle);
+		adapter_service_remove(adapter, r->handle);
 		btd_adapter_unref(r->adapter);
 		g_free(r);
 	}
diff --git a/src/sdpd-database.c b/src/sdpd-database.c
index 600ddbf..e4d4f98 100644
--- a/src/sdpd-database.c
+++ b/src/sdpd-database.c
@@ -36,7 +36,6 @@
 
 #include "sdpd.h"
 #include "log.h"
-#include "adapter.h"
 
 static sdp_list_t *service_db;
 static sdp_list_t *access_db;
@@ -254,13 +253,6 @@ int sdp_record_remove(uint32_t handle)
 
 	a = p->data;
 
-	if (bacmp(&a->device, BDADDR_ANY) != 0) {
-		struct btd_adapter *adapter = adapter_find(&a->device);
-		if (adapter)
-			adapter_service_remove(adapter, r);
-	} else
-		adapter_foreach(adapter_service_remove, r);
-
 	access_db = sdp_list_remove(access_db, a);
 	access_free(a);
 
-- 
1.8.4


^ 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