diff --git a/MAINTAINERS b/MAINTAINERS
index 4c5e9fe0f7db..e7b68c22f1f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -936,96 +936,21 @@ M:	joern@lazybastard.org
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
 
+BLUETOOTH DRIVERS
+P:	Marcel Holtmann
+M:	marcel@holtmann.org
+L:	linux-bluetooth@vger.kernel.org
+W:	http://www.bluez.org/
+S:	Maintained
+
 BLUETOOTH SUBSYSTEM
 P:	Marcel Holtmann
 M:	marcel@holtmann.org
-P:	Maxim Krasnyansky
-M:	maxk@qualcomm.com
 L:	linux-bluetooth@vger.kernel.org
-W:	http://bluez.sf.net
-W:	http://www.bluez.org
-W:	http://www.holtmann.org/linux/bluetooth/
+W:	http://www.bluez.org/
 T:	git kernel.org:/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git
 S:	Maintained
 
-BLUETOOTH RFCOMM LAYER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-P:	Maxim Krasnyansky
-M:	maxk@qualcomm.com
-S:	Maintained
-
-BLUETOOTH BNEP LAYER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-P:	Maxim Krasnyansky
-M:	maxk@qualcomm.com
-S:	Maintained
-
-BLUETOOTH CMTP LAYER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HIDP LAYER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI UART DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-P:	Maxim Krasnyansky
-M:	maxk@qualcomm.com
-S:	Maintained
-
-BLUETOOTH HCI USB DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-P:	Maxim Krasnyansky
-M:	maxk@qualcomm.com
-S:	Maintained
-
-BLUETOOTH HCI BCM203X DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI BPA10X DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI BFUSB DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI DTL1 DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI BLUECARD DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI BT3C DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI BTUART DRIVER
-P:	Marcel Holtmann
-M:	marcel@holtmann.org
-S:	Maintained
-
-BLUETOOTH HCI VHCI DRIVER
-P:	Maxim Krasnyansky
-M:	maxk@qualcomm.com
-S:	Maintained
-
 BONDING DRIVER
 P:	Jay Vosburgh
 M:	fubar@us.ibm.com
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index a235ca787465..7cb4029a5375 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -3,8 +3,8 @@ menu "Bluetooth device drivers"
 	depends on BT
 
 config BT_HCIUSB
-	tristate "HCI USB driver"
-	depends on USB
+	tristate "HCI USB driver (old version)"
+	depends on USB && BT_HCIBTUSB=n
 	help
 	  Bluetooth HCI USB driver.
 	  This driver is required if you want to use Bluetooth devices with
@@ -23,15 +23,13 @@ config BT_HCIUSB_SCO
 	  Say Y here to compile support for SCO over HCI USB.
 
 config BT_HCIBTUSB
-	tristate "HCI USB driver (alternate version)"
-	depends on USB && EXPERIMENTAL && BT_HCIUSB=n
+	tristate "HCI USB driver"
+	depends on USB
 	help
 	  Bluetooth HCI USB driver.
 	  This driver is required if you want to use Bluetooth devices with
 	  USB interface.
 
-          This driver is still experimental and has no SCO support.
-
 	  Say Y here to compile support for Bluetooth USB devices into the
 	  kernel or say M to compile it as module (btusb).
 
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 593b7c595038..27058477cc8b 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -60,7 +60,7 @@
 /* ======================== Module parameters ======================== */
 
 
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE("BT3CPCC.bin");
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 95ae9ba5661e..6a010681ecf3 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2,7 +2,7 @@
  *
  *  Generic Bluetooth USB driver
  *
- *  Copyright (C) 2005-2007  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.2"
+#define VERSION "0.3"
 
 static int ignore_dga;
 static int ignore_csr;
@@ -160,12 +160,16 @@ static struct usb_device_id blacklist_table[] = {
 	{ }	/* Terminating entry */
 };
 
+#define BTUSB_MAX_ISOC_FRAMES	10
+
 #define BTUSB_INTR_RUNNING	0
 #define BTUSB_BULK_RUNNING	1
+#define BTUSB_ISOC_RUNNING	2
 
 struct btusb_data {
 	struct hci_dev       *hdev;
 	struct usb_device    *udev;
+	struct usb_interface *isoc;
 
 	spinlock_t lock;
 
@@ -176,10 +180,15 @@ struct btusb_data {
 	struct usb_anchor tx_anchor;
 	struct usb_anchor intr_anchor;
 	struct usb_anchor bulk_anchor;
+	struct usb_anchor isoc_anchor;
 
 	struct usb_endpoint_descriptor *intr_ep;
 	struct usb_endpoint_descriptor *bulk_tx_ep;
 	struct usb_endpoint_descriptor *bulk_rx_ep;
+	struct usb_endpoint_descriptor *isoc_tx_ep;
+	struct usb_endpoint_descriptor *isoc_rx_ep;
+
+	int isoc_altsetting;
 };
 
 static void btusb_intr_complete(struct urb *urb)
@@ -195,6 +204,8 @@ static void btusb_intr_complete(struct urb *urb)
 		return;
 
 	if (urb->status == 0) {
+		hdev->stat.byte_rx += urb->actual_length;
+
 		if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
 						urb->transfer_buffer,
 						urb->actual_length) < 0) {
@@ -216,7 +227,7 @@ static void btusb_intr_complete(struct urb *urb)
 	}
 }
 
-static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
+static int btusb_submit_intr_urb(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hdev->driver_data;
 	struct urb *urb;
@@ -226,6 +237,9 @@ static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
 
 	BT_DBG("%s", hdev->name);
 
+	if (!data->intr_ep)
+		return -ENODEV;
+
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb)
 		return -ENOMEM;
@@ -274,6 +288,8 @@ static void btusb_bulk_complete(struct urb *urb)
 		return;
 
 	if (urb->status == 0) {
+		hdev->stat.byte_rx += urb->actual_length;
+
 		if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
 						urb->transfer_buffer,
 						urb->actual_length) < 0) {
@@ -295,7 +311,7 @@ static void btusb_bulk_complete(struct urb *urb)
 	}
 }
 
-static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
+static int btusb_submit_bulk_urb(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hdev->driver_data;
 	struct urb *urb;
@@ -305,6 +321,9 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
 
 	BT_DBG("%s", hdev->name);
 
+	if (!data->bulk_rx_ep)
+		return -ENODEV;
+
 	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 		return -ENOMEM;
@@ -339,6 +358,127 @@ static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
 	return err;
 }
 
+static void btusb_isoc_complete(struct urb *urb)
+{
+	struct hci_dev *hdev = urb->context;
+	struct btusb_data *data = hdev->driver_data;
+	int i, err;
+
+	BT_DBG("%s urb %p status %d count %d", hdev->name,
+					urb, urb->status, urb->actual_length);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return;
+
+	if (urb->status == 0) {
+		for (i = 0; i < urb->number_of_packets; i++) {
+			unsigned int offset = urb->iso_frame_desc[i].offset;
+			unsigned int length = urb->iso_frame_desc[i].actual_length;
+
+			if (urb->iso_frame_desc[i].status)
+				continue;
+
+			hdev->stat.byte_rx += length;
+
+			if (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
+						urb->transfer_buffer + offset,
+								length) < 0) {
+				BT_ERR("%s corrupted SCO packet", hdev->name);
+				hdev->stat.err_rx++;
+			}
+		}
+	}
+
+	if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
+		return;
+
+	usb_anchor_urb(urb, &data->isoc_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0) {
+		BT_ERR("%s urb %p failed to resubmit (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+	}
+}
+
+static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
+{
+	int i, offset = 0;
+
+	BT_DBG("len %d mtu %d", len, mtu);
+
+	for (i = 0; i < BTUSB_MAX_ISOC_FRAMES && len >= mtu;
+					i++, offset += mtu, len -= mtu) {
+		urb->iso_frame_desc[i].offset = offset;
+		urb->iso_frame_desc[i].length = mtu;
+	}
+
+	if (len && i < BTUSB_MAX_ISOC_FRAMES) {
+		urb->iso_frame_desc[i].offset = offset;
+		urb->iso_frame_desc[i].length = len;
+		i++;
+	}
+
+	urb->number_of_packets = i;
+}
+
+static int btusb_submit_isoc_urb(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hdev->driver_data;
+	struct urb *urb;
+	unsigned char *buf;
+	unsigned int pipe;
+	int err, size;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!data->isoc_rx_ep)
+		return -ENODEV;
+
+	urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) *
+						BTUSB_MAX_ISOC_FRAMES;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
+
+	urb->dev      = data->udev;
+	urb->pipe     = pipe;
+	urb->context  = hdev;
+	urb->complete = btusb_isoc_complete;
+	urb->interval = data->isoc_rx_ep->bInterval;
+
+	urb->transfer_flags  = URB_FREE_BUFFER | URB_ISO_ASAP;
+	urb->transfer_buffer = buf;
+	urb->transfer_buffer_length = size;
+
+	__fill_isoc_descriptor(urb, size,
+			le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
+
+	usb_anchor_urb(urb, &data->isoc_anchor);
+
+	err = usb_submit_urb(urb, GFP_KERNEL);
+	if (err < 0) {
+		BT_ERR("%s urb %p submission failed (%d)",
+						hdev->name, urb, -err);
+		usb_unanchor_urb(urb);
+		kfree(buf);
+	}
+
+	usb_free_urb(urb);
+
+	return err;
+}
+
 static void btusb_tx_complete(struct urb *urb)
 {
 	struct sk_buff *skb = urb->context;
@@ -392,6 +532,9 @@ static int btusb_close(struct hci_dev *hdev)
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
+	clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+	usb_kill_anchored_urbs(&data->intr_anchor);
+
 	clear_bit(BTUSB_BULK_RUNNING, &data->flags);
 	usb_kill_anchored_urbs(&data->bulk_anchor);
 
@@ -453,6 +596,9 @@ static int btusb_send_frame(struct sk_buff *skb)
 		break;
 
 	case HCI_ACLDATA_PKT:
+		if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1)
+			return -ENODEV;
+
 		urb = usb_alloc_urb(0, GFP_ATOMIC);
 		if (!urb)
 			return -ENOMEM;
@@ -467,9 +613,31 @@ static int btusb_send_frame(struct sk_buff *skb)
 		break;
 
 	case HCI_SCODATA_PKT:
+		if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1)
+			return -ENODEV;
+
+		urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
+		if (!urb)
+			return -ENOMEM;
+
+		pipe = usb_sndisocpipe(data->udev,
+					data->isoc_tx_ep->bEndpointAddress);
+
+		urb->dev      = data->udev;
+		urb->pipe     = pipe;
+		urb->context  = skb;
+		urb->complete = btusb_tx_complete;
+		urb->interval = data->isoc_tx_ep->bInterval;
+
+		urb->transfer_flags  = URB_ISO_ASAP;
+		urb->transfer_buffer = skb->data;
+		urb->transfer_buffer_length = skb->len;
+
+		__fill_isoc_descriptor(urb, skb->len,
+				le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
+
 		hdev->stat.sco_tx++;
-		kfree_skb(skb);
-		return 0;
+		break;
 
 	default:
 		return -EILSEQ;
@@ -508,22 +676,86 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 		schedule_work(&data->work);
 }
 
+static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting)
+{
+	struct btusb_data *data = hdev->driver_data;
+	struct usb_interface *intf = data->isoc;
+	struct usb_endpoint_descriptor *ep_desc;
+	int i, err;
+
+	if (!data->isoc)
+		return -ENODEV;
+
+	err = usb_set_interface(data->udev, 1, altsetting);
+	if (err < 0) {
+		BT_ERR("%s setting interface failed (%d)", hdev->name, -err);
+		return err;
+	}
+
+	data->isoc_altsetting = altsetting;
+
+	data->isoc_tx_ep = NULL;
+	data->isoc_rx_ep = NULL;
+
+	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+		ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+		if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) {
+			data->isoc_tx_ep = ep_desc;
+			continue;
+		}
+
+		if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) {
+			data->isoc_rx_ep = ep_desc;
+			continue;
+		}
+	}
+
+	if (!data->isoc_tx_ep || !data->isoc_rx_ep) {
+		BT_ERR("%s invalid SCO descriptors", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static void btusb_work(struct work_struct *work)
 {
 	struct btusb_data *data = container_of(work, struct btusb_data, work);
 	struct hci_dev *hdev = data->hdev;
 
-	if (hdev->conn_hash.acl_num == 0) {
+	if (hdev->conn_hash.acl_num > 0) {
+		if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+			if (btusb_submit_bulk_urb(hdev) < 0)
+				clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+			else
+				btusb_submit_bulk_urb(hdev);
+		}
+	} else {
 		clear_bit(BTUSB_BULK_RUNNING, &data->flags);
 		usb_kill_anchored_urbs(&data->bulk_anchor);
-		return;
 	}
 
-	if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
-		if (btusb_submit_bulk_urb(hdev) < 0)
-			clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-		else
-			btusb_submit_bulk_urb(hdev);
+	if (hdev->conn_hash.sco_num > 0) {
+		if (data->isoc_altsetting != 2) {
+			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+			usb_kill_anchored_urbs(&data->isoc_anchor);
+
+			if (__set_isoc_interface(hdev, 2) < 0)
+				return;
+		}
+
+		if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
+			if (btusb_submit_isoc_urb(hdev) < 0)
+				clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+			else
+				btusb_submit_isoc_urb(hdev);
+		}
+	} else {
+		clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+		usb_kill_anchored_urbs(&data->isoc_anchor);
+
+		__set_isoc_interface(hdev, 0);
 	}
 }
 
@@ -597,6 +829,7 @@ static int btusb_probe(struct usb_interface *intf,
 	init_usb_anchor(&data->tx_anchor);
 	init_usb_anchor(&data->intr_anchor);
 	init_usb_anchor(&data->bulk_anchor);
+	init_usb_anchor(&data->isoc_anchor);
 
 	hdev = hci_alloc_dev();
 	if (!hdev) {
@@ -620,6 +853,9 @@ static int btusb_probe(struct usb_interface *intf,
 
 	hdev->owner = THIS_MODULE;
 
+	/* interface numbers are hardcoded in the spec */
+	data->isoc = usb_ifnum_to_if(data->udev, 1);
+
 	if (reset || id->driver_info & BTUSB_RESET)
 		set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
 
@@ -628,11 +864,16 @@ static int btusb_probe(struct usb_interface *intf,
 			set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
 	}
 
+	if (id->driver_info & BTUSB_BROKEN_ISOC)
+		data->isoc = NULL;
+
 	if (id->driver_info & BTUSB_SNIFFER) {
-		struct usb_device *udev = interface_to_usbdev(intf);
+		struct usb_device *udev = data->udev;
 
 		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
 			set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
+		data->isoc = NULL;
 	}
 
 	if (id->driver_info & BTUSB_BCM92035) {
@@ -646,6 +887,16 @@ static int btusb_probe(struct usb_interface *intf,
 		}
 	}
 
+	if (data->isoc) {
+		err = usb_driver_claim_interface(&btusb_driver,
+							data->isoc, NULL);
+		if (err < 0) {
+			hci_free_dev(hdev);
+			kfree(data);
+			return err;
+		}
+	}
+
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		hci_free_dev(hdev);
@@ -670,6 +921,9 @@ static void btusb_disconnect(struct usb_interface *intf)
 
 	hdev = data->hdev;
 
+	if (data->isoc)
+		usb_driver_release_interface(&btusb_driver, data->isoc);
+
 	usb_set_intfdata(intf, NULL);
 
 	hci_unregister_dev(hdev);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 69df187d74ce..8dfcf77cb717 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -577,7 +577,7 @@ module_exit(hci_uart_exit);
 module_param(reset, bool, 0644);
 MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index e397572bf574..3c453924f838 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -1130,7 +1130,7 @@ module_param(isoc, int, 0644);
 MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support");
 #endif
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index d97700aa54a9..7320a71b6368 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -377,7 +377,7 @@ module_exit(vhci_exit);
 module_param(minor, int, 0444);
 MODULE_PARM_DESC(minor, "Miscellaneous minor device number");
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 4e59df5f8e05..1edfdf4c095b 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -456,7 +456,7 @@ static void __exit bt_exit(void)
 subsys_initcall(bt_init);
 module_exit(bt_exit);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 12bba6207a8d..80ba30cf4b68 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -736,7 +736,7 @@ MODULE_PARM_DESC(compress_src, "Compress sources headers");
 module_param(compress_dst, bool, 0644);
 MODULE_PARM_DESC(compress_dst, "Compress destination headers");
 
-MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index c85bf8f678dc..f4f6615cad9f 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -3,8 +3,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <linux/platform_device.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
@@ -12,10 +10,164 @@
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
+
+struct class *bt_class = NULL;
+EXPORT_SYMBOL_GPL(bt_class);
+
 static struct workqueue_struct *btaddconn;
 static struct workqueue_struct *btdelconn;
 
-static inline char *typetostr(int type)
+static inline char *link_typetostr(int type)
+{
+	switch (type) {
+	case ACL_LINK:
+		return "ACL";
+	case SCO_LINK:
+		return "SCO";
+	case ESCO_LINK:
+		return "eSCO";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hci_conn *conn = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", link_typetostr(conn->type));
+}
+
+static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hci_conn *conn = dev_get_drvdata(dev);
+	bdaddr_t bdaddr;
+	baswap(&bdaddr, &conn->dst);
+	return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hci_conn *conn = dev_get_drvdata(dev);
+
+	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+				conn->features[0], conn->features[1],
+				conn->features[2], conn->features[3],
+				conn->features[4], conn->features[5],
+				conn->features[6], conn->features[7]);
+}
+
+#define LINK_ATTR(_name,_mode,_show,_store) \
+struct device_attribute link_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
+static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);
+static LINK_ATTR(features, S_IRUGO, show_link_features, NULL);
+
+static struct attribute *bt_link_attrs[] = {
+	&link_attr_type.attr,
+	&link_attr_address.attr,
+	&link_attr_features.attr,
+	NULL
+};
+
+static struct attribute_group bt_link_group = {
+	.attrs = bt_link_attrs,
+};
+
+static struct attribute_group *bt_link_groups[] = {
+	&bt_link_group,
+	NULL
+};
+
+static void bt_link_release(struct device *dev)
+{
+	void *data = dev_get_drvdata(dev);
+	kfree(data);
+}
+
+static struct device_type bt_link = {
+	.name    = "link",
+	.groups  = bt_link_groups,
+	.release = bt_link_release,
+};
+
+static void add_conn(struct work_struct *work)
+{
+	struct hci_conn *conn = container_of(work, struct hci_conn, work);
+
+	flush_workqueue(btdelconn);
+
+	if (device_add(&conn->dev) < 0) {
+		BT_ERR("Failed to register connection device");
+		return;
+	}
+}
+
+void hci_conn_add_sysfs(struct hci_conn *conn)
+{
+	struct hci_dev *hdev = conn->hdev;
+
+	BT_DBG("conn %p", conn);
+
+	conn->dev.type = &bt_link;
+	conn->dev.class = bt_class;
+	conn->dev.parent = &hdev->dev;
+
+	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d",
+					hdev->name, conn->handle);
+
+	dev_set_drvdata(&conn->dev, conn);
+
+	device_initialize(&conn->dev);
+
+	INIT_WORK(&conn->work, add_conn);
+
+	queue_work(btaddconn, &conn->work);
+}
+
+/*
+ * The rfcomm tty device will possibly retain even when conn
+ * is down, and sysfs doesn't support move zombie device,
+ * so we should move the device before conn device is destroyed.
+ */
+static int __match_tty(struct device *dev, void *data)
+{
+	return !strncmp(dev->bus_id, "rfcomm", 6);
+}
+
+static void del_conn(struct work_struct *work)
+{
+	struct hci_conn *conn = container_of(work, struct hci_conn, work);
+	struct hci_dev *hdev = conn->hdev;
+
+	while (1) {
+		struct device *dev;
+
+		dev = device_find_child(&conn->dev, NULL, __match_tty);
+		if (!dev)
+			break;
+		device_move(dev, NULL);
+		put_device(dev);
+	}
+
+	device_del(&conn->dev);
+	put_device(&conn->dev);
+	hci_dev_put(hdev);
+}
+
+void hci_conn_del_sysfs(struct hci_conn *conn)
+{
+	BT_DBG("conn %p", conn);
+
+	if (!device_is_registered(&conn->dev))
+		return;
+
+	INIT_WORK(&conn->work, del_conn);
+
+	queue_work(btdelconn, &conn->work);
+}
+
+static inline char *host_typetostr(int type)
 {
 	switch (type) {
 	case HCI_VIRTUAL:
@@ -40,7 +192,7 @@ static inline char *typetostr(int type)
 static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	return sprintf(buf, "%s\n", typetostr(hdev->type));
+	return sprintf(buf, "%s\n", host_typetostr(hdev->type));
 }
 
 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -221,183 +373,62 @@ static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
 static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
 				show_sniff_min_interval, store_sniff_min_interval);
 
-static struct device_attribute *bt_attrs[] = {
-	&dev_attr_type,
-	&dev_attr_name,
-	&dev_attr_class,
-	&dev_attr_address,
-	&dev_attr_features,
-	&dev_attr_manufacturer,
-	&dev_attr_hci_version,
-	&dev_attr_hci_revision,
-	&dev_attr_inquiry_cache,
-	&dev_attr_idle_timeout,
-	&dev_attr_sniff_max_interval,
-	&dev_attr_sniff_min_interval,
+static struct attribute *bt_host_attrs[] = {
+	&dev_attr_type.attr,
+	&dev_attr_name.attr,
+	&dev_attr_class.attr,
+	&dev_attr_address.attr,
+	&dev_attr_features.attr,
+	&dev_attr_manufacturer.attr,
+	&dev_attr_hci_version.attr,
+	&dev_attr_hci_revision.attr,
+	&dev_attr_inquiry_cache.attr,
+	&dev_attr_idle_timeout.attr,
+	&dev_attr_sniff_max_interval.attr,
+	&dev_attr_sniff_min_interval.attr,
 	NULL
 };
 
-static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct hci_conn *conn = dev_get_drvdata(dev);
-	return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO");
-}
+static struct attribute_group bt_host_group = {
+	.attrs = bt_host_attrs,
+};
 
-static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct hci_conn *conn = dev_get_drvdata(dev);
-	bdaddr_t bdaddr;
-	baswap(&bdaddr, &conn->dst);
-	return sprintf(buf, "%s\n", batostr(&bdaddr));
-}
-
-static ssize_t show_conn_features(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct hci_conn *conn = dev_get_drvdata(dev);
-
-	return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-				conn->features[0], conn->features[1],
-				conn->features[2], conn->features[3],
-				conn->features[4], conn->features[5],
-				conn->features[6], conn->features[7]);
-}
-
-#define CONN_ATTR(_name,_mode,_show,_store) \
-struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
-static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
-static CONN_ATTR(features, S_IRUGO, show_conn_features, NULL);
-
-static struct device_attribute *conn_attrs[] = {
-	&conn_attr_type,
-	&conn_attr_address,
-	&conn_attr_features,
+static struct attribute_group *bt_host_groups[] = {
+	&bt_host_group,
 	NULL
 };
 
-struct class *bt_class = NULL;
-EXPORT_SYMBOL_GPL(bt_class);
-
-static struct bus_type bt_bus = {
-	.name	= "bluetooth",
-};
-
-static struct platform_device *bt_platform;
-
-static void bt_release(struct device *dev)
+static void bt_host_release(struct device *dev)
 {
 	void *data = dev_get_drvdata(dev);
 	kfree(data);
 }
 
-static void add_conn(struct work_struct *work)
-{
-	struct hci_conn *conn = container_of(work, struct hci_conn, work);
-	int i;
-
-	flush_workqueue(btdelconn);
-
-	if (device_add(&conn->dev) < 0) {
-		BT_ERR("Failed to register connection device");
-		return;
-	}
-
-	for (i = 0; conn_attrs[i]; i++)
-		if (device_create_file(&conn->dev, conn_attrs[i]) < 0)
-			BT_ERR("Failed to create connection attribute");
-}
-
-void hci_conn_add_sysfs(struct hci_conn *conn)
-{
-	struct hci_dev *hdev = conn->hdev;
-
-	BT_DBG("conn %p", conn);
-
-	conn->dev.bus = &bt_bus;
-	conn->dev.parent = &hdev->dev;
-
-	conn->dev.release = bt_release;
-
-	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d",
-					hdev->name, conn->handle);
-
-	dev_set_drvdata(&conn->dev, conn);
-
-	device_initialize(&conn->dev);
-
-	INIT_WORK(&conn->work, add_conn);
-
-	queue_work(btaddconn, &conn->work);
-}
-
-/*
- * The rfcomm tty device will possibly retain even when conn
- * is down, and sysfs doesn't support move zombie device,
- * so we should move the device before conn device is destroyed.
- */
-static int __match_tty(struct device *dev, void *data)
-{
-	return !strncmp(dev->bus_id, "rfcomm", 6);
-}
-
-static void del_conn(struct work_struct *work)
-{
-	struct hci_conn *conn = container_of(work, struct hci_conn, work);
-	struct hci_dev *hdev = conn->hdev;
-
-	while (1) {
-		struct device *dev;
-
-		dev = device_find_child(&conn->dev, NULL, __match_tty);
-		if (!dev)
-			break;
-		device_move(dev, NULL);
-		put_device(dev);
-	}
-
-	device_del(&conn->dev);
-	put_device(&conn->dev);
-	hci_dev_put(hdev);
-}
-
-void hci_conn_del_sysfs(struct hci_conn *conn)
-{
-	BT_DBG("conn %p", conn);
-
-	if (!device_is_registered(&conn->dev))
-		return;
-
-	INIT_WORK(&conn->work, del_conn);
-
-	queue_work(btdelconn, &conn->work);
-}
+static struct device_type bt_host = {
+	.name    = "host",
+	.groups  = bt_host_groups,
+	.release = bt_host_release,
+};
 
 int hci_register_sysfs(struct hci_dev *hdev)
 {
 	struct device *dev = &hdev->dev;
-	unsigned int i;
 	int err;
 
 	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
-	dev->bus = &bt_bus;
+	dev->type = &bt_host;
+	dev->class = bt_class;
 	dev->parent = hdev->parent;
 
 	strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
 
-	dev->release = bt_release;
-
 	dev_set_drvdata(dev, hdev);
 
 	err = device_register(dev);
 	if (err < 0)
 		return err;
 
-	for (i = 0; bt_attrs[i]; i++)
-		if (device_create_file(dev, bt_attrs[i]) < 0)
-			BT_ERR("Failed to create device attribute");
-
 	return 0;
 }
 
@@ -410,59 +441,30 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
 
 int __init bt_sysfs_init(void)
 {
-	int err;
-
 	btaddconn = create_singlethread_workqueue("btaddconn");
-	if (!btaddconn) {
-		err = -ENOMEM;
-		goto out;
-	}
+	if (!btaddconn)
+		return -ENOMEM;
 
 	btdelconn = create_singlethread_workqueue("btdelconn");
 	if (!btdelconn) {
-		err = -ENOMEM;
-		goto out_del;
+		destroy_workqueue(btaddconn);
+		return -ENOMEM;
 	}
 
-	bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
-	if (IS_ERR(bt_platform)) {
-		err = PTR_ERR(bt_platform);
-		goto out_platform;
-	}
-
-	err = bus_register(&bt_bus);
-	if (err < 0)
-		goto out_bus;
-
 	bt_class = class_create(THIS_MODULE, "bluetooth");
 	if (IS_ERR(bt_class)) {
-		err = PTR_ERR(bt_class);
-		goto out_class;
+		destroy_workqueue(btdelconn);
+		destroy_workqueue(btaddconn);
+		return PTR_ERR(bt_class);
 	}
 
 	return 0;
-
-out_class:
-	bus_unregister(&bt_bus);
-out_bus:
-	platform_device_unregister(bt_platform);
-out_platform:
-	destroy_workqueue(btdelconn);
-out_del:
-	destroy_workqueue(btaddconn);
-out:
-	return err;
 }
 
 void bt_sysfs_cleanup(void)
 {
 	destroy_workqueue(btaddconn);
-
 	destroy_workqueue(btdelconn);
 
 	class_destroy(bt_class);
-
-	bus_unregister(&bt_bus);
-
-	platform_device_unregister(bt_platform);
 }
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index c1239852834a..3396d5bdef1c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2516,7 +2516,7 @@ EXPORT_SYMBOL(l2cap_load);
 module_init(l2cap_init);
 module_exit(l2cap_exit);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 6cfc7ba611b3..ba537fae0a4c 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2115,7 +2115,7 @@ MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel");
 module_param(l2cap_mtu, uint, 0644);
 MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection");
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 8cda49874868..a16011fedc1d 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1002,7 +1002,7 @@ module_exit(sco_exit);
 module_param(disable_esco, bool, 0644);
 MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");