linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH 0/2] broadcom patchram firmware loader
@ 2012-08-14 14:24 Jesse Sung
  2012-08-14 14:24 ` [RFC][PATCH 1/2] Implement " Jesse Sung
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Jesse Sung @ 2012-08-14 14:24 UTC (permalink / raw)
  To: linux-bluetooth

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

This is a multi-part message in MIME format.

[-- Attachment #2: Type: text/plain, Size: 937 bytes --]


There is a user space firmware loading tool which can be found at
http://article.gmane.org/gmane.linux.bluez.kernel/17932

This tool requires hci device to do the firmware loading, but this
may cause some race condition between patchram tool and bluetoothd
or something that also works on hci interface.

Also it needs some hooks to make firmware loads after bootup, s3,
s4, rfkill, and device hotplug events. Implement this loader in kernel
module would make things more easier.


Wen-chien Jesse Sung (2):
  Implement broadcom patchram firmware loader
  Cache firmware images for later use

 drivers/bluetooth/btusb.c |  154 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 147 insertions(+), 7 deletions(-)

-- 
1.7.9.5

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC][PATCH 1/2] Implement broadcom patchram firmware loader
  2012-08-14 14:24 [RFC][PATCH 0/2] broadcom patchram firmware loader Jesse Sung
@ 2012-08-14 14:24 ` Jesse Sung
  2012-08-14 14:24 ` [RFC][PATCH 2/2] Cache firmware images for later use Jesse Sung
  2012-08-14 17:14 ` [RFC][PATCH 0/2] broadcom patchram firmware loader Joao Paulo Rechi Vita
  2 siblings, 0 replies; 6+ messages in thread
From: Jesse Sung @ 2012-08-14 14:24 UTC (permalink / raw)
  To: linux-bluetooth

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

This is a multi-part message in MIME format.

[-- Attachment #2: Type: text/plain, Size: 200 bytes --]


Signed-off-by: Wen-chien Jesse Sung <jesse.sung@canonical.com>
---
 drivers/bluetooth/btusb.c |  109 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 103 insertions(+), 6 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Implement-broadcom-patchram-firmware-loader.patch --]
[-- Type: text/x-patch; name="0001-Implement-broadcom-patchram-firmware-loader.patch", Size: 5096 bytes --]

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index cef3bac..b60a2ae 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -23,6 +23,8 @@
 
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -47,6 +49,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_BROKEN_ISOC	0x20
 #define BTUSB_WRONG_SCO_MTU	0x40
 #define BTUSB_ATH3012		0x80
+#define BTUSB_BCM_PATCHRAM	0x100
 
 static struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -93,13 +96,16 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x0c10, 0x0000) },
 
 	/* Broadcom BCM20702A0 */
+	{ USB_DEVICE(0x0489, 0xe031), .driver_info = BTUSB_BCM_PATCHRAM },
 	{ USB_DEVICE(0x0489, 0xe042) },
+	{ USB_DEVICE(0x0a5c, 0x21d3), .driver_info = BTUSB_BCM_PATCHRAM },
+	{ USB_DEVICE(0x0a5c, 0x21d7), .driver_info = BTUSB_BCM_PATCHRAM },
 	{ USB_DEVICE(0x0a5c, 0x21e3) },
-	{ USB_DEVICE(0x0a5c, 0x21e6) },
+	{ USB_DEVICE(0x0a5c, 0x21e6), .driver_info = BTUSB_BCM_PATCHRAM },
 	{ USB_DEVICE(0x0a5c, 0x21e8) },
-	{ USB_DEVICE(0x0a5c, 0x21f3) },
-	{ USB_DEVICE(0x0a5c, 0x21f4) },
-	{ USB_DEVICE(0x413c, 0x8197) },
+	{ USB_DEVICE(0x0a5c, 0x21f3), .driver_info = BTUSB_BCM_PATCHRAM },
+	{ USB_DEVICE(0x0a5c, 0x21f4), .driver_info = BTUSB_BCM_PATCHRAM },
+	{ USB_DEVICE(0x413c, 0x8197), .driver_info = BTUSB_BCM_PATCHRAM },
 
 	/* Foxconn - Hon Hai */
 	{ USB_DEVICE(0x0489, 0xe033) },
@@ -195,6 +201,37 @@ static struct usb_device_id blacklist_table[] = {
 	{ }	/* Terminating entry */
 };
 
+#define PATCHRAM_TIMEOUT	1000
+#define FW_0489_E031		"fw-0489_e031.hcd"
+#define FW_0A5C_21D3		"fw-0a5c_21d3.hcd"
+#define FW_0A5C_21D7		"fw-0a5c_21d7.hcd"
+#define FW_0A5C_21E6		"fw-0a5c_21e6.hcd"
+#define FW_0A5C_21F3		"fw-0a5c_21f3.hcd"
+#define FW_0A5C_21F4		"fw-0a5c_21f4.hcd"
+#define FW_413C_8197		"fw-413c_8197.hcd"
+
+MODULE_FIRMWARE(FW_0489_E031);
+MODULE_FIRMWARE(FW_0A5C_21D3);
+MODULE_FIRMWARE(FW_0A5C_21D7);
+MODULE_FIRMWARE(FW_0A5C_21E6);
+MODULE_FIRMWARE(FW_0A5C_21F3);
+MODULE_FIRMWARE(FW_0A5C_21F4);
+MODULE_FIRMWARE(FW_413C_8197);
+
+static struct usb_device_id patchram_table[] = {
+	/* Dell DW1704 */
+	{ USB_DEVICE(0x0a5c, 0x21d3), .driver_info = (kernel_ulong_t) FW_0A5C_21D3 },
+	{ USB_DEVICE(0x0a5c, 0x21d7), .driver_info = (kernel_ulong_t) FW_0A5C_21D7 },
+	/* Dell DW380 */
+	{ USB_DEVICE(0x413c, 0x8197), .driver_info = (kernel_ulong_t) FW_413C_8197 },
+	/* FoxConn Hon Hai */
+	{ USB_DEVICE(0x0489, 0xe031), .driver_info = (kernel_ulong_t) FW_0489_E031 },
+	/* Lenovo */
+	{ USB_DEVICE(0x0a5c, 0x21e6), .driver_info = (kernel_ulong_t) FW_0A5C_21E6 },
+	{ USB_DEVICE(0x0a5c, 0x21f3), .driver_info = (kernel_ulong_t) FW_0A5C_21F3 },
+	{ USB_DEVICE(0x0a5c, 0x21f4), .driver_info = (kernel_ulong_t) FW_0A5C_21F4 },
+};
+
 #define BTUSB_MAX_ISOC_FRAMES	10
 
 #define BTUSB_INTR_RUNNING	0
@@ -912,6 +949,55 @@ static void btusb_waker(struct work_struct *work)
 	usb_autopm_put_interface(data->intf);
 }
 
+static inline void load_patchram_fw(struct usb_device *udev, const struct usb_device_id *id)
+{
+	size_t pos = 0;
+	int err = 0;
+	const struct firmware *fw;
+
+	unsigned char reset_cmd[] = { 0x03, 0x0c, 0x00 };
+	unsigned char download_cmd[] = { 0x2e, 0xfc, 0x00 };
+
+	if (request_firmware(&fw, (const char *) id->driver_info, &udev->dev) < 0) {
+		BT_INFO("can't load firmware, may not work correctly");
+		return;
+	}
+
+	if (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
+		reset_cmd, sizeof(reset_cmd), PATCHRAM_TIMEOUT) < 0) {
+		err = -1;
+		goto out;
+	}
+	msleep(300);
+
+	if (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
+		download_cmd, sizeof(download_cmd), PATCHRAM_TIMEOUT) < 0) {
+		err = -1;
+		goto out;
+	}
+	msleep(300);
+
+	while (pos < fw->size) {
+		size_t len;
+		len = fw->data[pos + 2] + 3;
+		if ((pos + len > fw->size) ||
+			(usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+			USB_TYPE_CLASS, 0, 0, (void *)fw->data + pos, len,
+			PATCHRAM_TIMEOUT) < 0)) {
+			err = -1;
+			goto out;
+		}
+		pos += len;
+	}
+
+	err = (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
+		reset_cmd, sizeof(reset_cmd), PATCHRAM_TIMEOUT) < 0);
+out:
+	if (err)
+		BT_INFO("fail to load firmware, may not work correctly");
+	release_firmware(fw);
+}
+
 static int btusb_probe(struct usb_interface *intf,
 				const struct usb_device_id *id)
 {
@@ -1076,15 +1162,26 @@ static int btusb_probe(struct usb_interface *intf,
 		}
 	}
 
+	usb_set_intfdata(intf, data);
+
+	if (id->driver_info & BTUSB_BCM_PATCHRAM) {
+		const struct usb_device_id *match;
+		match = usb_match_id(intf, patchram_table);
+		if (match) {
+			btusb_open(hdev);
+			load_patchram_fw(interface_to_usbdev(intf), match);
+			btusb_close(hdev);
+		}
+	}
+
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		hci_free_dev(hdev);
+		usb_set_intfdata(intf, NULL);
 		kfree(data);
 		return err;
 	}
 
-	usb_set_intfdata(intf, data);
-
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC][PATCH 2/2] Cache firmware images for later use
  2012-08-14 14:24 [RFC][PATCH 0/2] broadcom patchram firmware loader Jesse Sung
  2012-08-14 14:24 ` [RFC][PATCH 1/2] Implement " Jesse Sung
@ 2012-08-14 14:24 ` Jesse Sung
  2012-08-14 17:14 ` [RFC][PATCH 0/2] broadcom patchram firmware loader Joao Paulo Rechi Vita
  2 siblings, 0 replies; 6+ messages in thread
From: Jesse Sung @ 2012-08-14 14:24 UTC (permalink / raw)
  To: linux-bluetooth

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

This is a multi-part message in MIME format.

[-- Attachment #2: Type: text/plain, Size: 348 bytes --]


Since request_firmware() may fail when resume from suspend, store
used firmware image in ram to make sure that we can have what we need
on resume.

Signed-off-by: Wen-chien Jesse Sung <jesse.sung@canonical.com>
---
 drivers/bluetooth/btusb.c |   77 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 60 insertions(+), 17 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Cache-firmware-images-for-later-use.patch --]
[-- Type: text/x-patch; name="0002-Cache-firmware-images-for-later-use.patch", Size: 4390 bytes --]

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index b60a2ae..6559c1b 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -218,18 +218,34 @@ MODULE_FIRMWARE(FW_0A5C_21F3);
 MODULE_FIRMWARE(FW_0A5C_21F4);
 MODULE_FIRMWARE(FW_413C_8197);
 
+struct firmware_cache {
+	const char *filename;
+	u8* data;
+	size_t size;
+};
+
+static struct firmware_cache firmware[] = {
+	{ .filename = FW_0A5C_21D3, },
+	{ .filename = FW_0A5C_21D7, },
+	{ .filename = FW_413C_8197, },
+	{ .filename = FW_0489_E031, },
+	{ .filename = FW_0A5C_21E6, },
+	{ .filename = FW_0A5C_21F3, },
+	{ .filename = FW_0A5C_21F4, },
+};
+
 static struct usb_device_id patchram_table[] = {
 	/* Dell DW1704 */
-	{ USB_DEVICE(0x0a5c, 0x21d3), .driver_info = (kernel_ulong_t) FW_0A5C_21D3 },
-	{ USB_DEVICE(0x0a5c, 0x21d7), .driver_info = (kernel_ulong_t) FW_0A5C_21D7 },
+	{ USB_DEVICE(0x0a5c, 0x21d3), .driver_info = (kernel_ulong_t) &firmware[0] },
+	{ USB_DEVICE(0x0a5c, 0x21d7), .driver_info = (kernel_ulong_t) &firmware[1] },
 	/* Dell DW380 */
-	{ USB_DEVICE(0x413c, 0x8197), .driver_info = (kernel_ulong_t) FW_413C_8197 },
+	{ USB_DEVICE(0x413c, 0x8197), .driver_info = (kernel_ulong_t) &firmware[2] },
 	/* FoxConn Hon Hai */
-	{ USB_DEVICE(0x0489, 0xe031), .driver_info = (kernel_ulong_t) FW_0489_E031 },
+	{ USB_DEVICE(0x0489, 0xe031), .driver_info = (kernel_ulong_t) &firmware[3] },
 	/* Lenovo */
-	{ USB_DEVICE(0x0a5c, 0x21e6), .driver_info = (kernel_ulong_t) FW_0A5C_21E6 },
-	{ USB_DEVICE(0x0a5c, 0x21f3), .driver_info = (kernel_ulong_t) FW_0A5C_21F3 },
-	{ USB_DEVICE(0x0a5c, 0x21f4), .driver_info = (kernel_ulong_t) FW_0A5C_21F4 },
+	{ USB_DEVICE(0x0a5c, 0x21e6), .driver_info = (kernel_ulong_t) &firmware[4] },
+	{ USB_DEVICE(0x0a5c, 0x21f3), .driver_info = (kernel_ulong_t) &firmware[5] },
+	{ USB_DEVICE(0x0a5c, 0x21f4), .driver_info = (kernel_ulong_t) &firmware[6] },
 };
 
 #define BTUSB_MAX_ISOC_FRAMES	10
@@ -953,14 +969,27 @@ static inline void load_patchram_fw(struct usb_device *udev, const struct usb_de
 {
 	size_t pos = 0;
 	int err = 0;
-	const struct firmware *fw;
+	struct firmware_cache *fwcache;
 
 	unsigned char reset_cmd[] = { 0x03, 0x0c, 0x00 };
 	unsigned char download_cmd[] = { 0x2e, 0xfc, 0x00 };
 
-	if (request_firmware(&fw, (const char *) id->driver_info, &udev->dev) < 0) {
-		BT_INFO("can't load firmware, may not work correctly");
-		return;
+	fwcache = (struct firmware_cache *)id->driver_info;
+	if (!fwcache->data) {
+		const struct firmware *fw;
+		if (request_firmware(&fw, fwcache->filename, &udev->dev) < 0) {
+			BT_INFO("can't load firmware, may not work correctly");
+			return;
+		}
+		fwcache->data = kmalloc(fw->size, GFP_KERNEL);
+		if (!fwcache->data) {
+			BT_INFO("OOM");
+			release_firmware(fw);
+			return;
+		}
+		fwcache->size = fw->size;
+		memcpy(fwcache->data, fw->data, fwcache->size);
+		release_firmware(fw);
 	}
 
 	if (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
@@ -977,12 +1006,12 @@ static inline void load_patchram_fw(struct usb_device *udev, const struct usb_de
 	}
 	msleep(300);
 
-	while (pos < fw->size) {
+	while (pos < fwcache->size) {
 		size_t len;
-		len = fw->data[pos + 2] + 3;
-		if ((pos + len > fw->size) ||
+		len = fwcache->data[pos + 2] + 3;
+		if ((pos + len > fwcache->size) ||
 			(usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-			USB_TYPE_CLASS, 0, 0, (void *)fw->data + pos, len,
+			USB_TYPE_CLASS, 0, 0, (void *)(fwcache->data + pos), len,
 			PATCHRAM_TIMEOUT) < 0)) {
 			err = -1;
 			goto out;
@@ -995,7 +1024,6 @@ static inline void load_patchram_fw(struct usb_device *udev, const struct usb_de
 out:
 	if (err)
 		BT_INFO("fail to load firmware, may not work correctly");
-	release_firmware(fw);
 }
 
 static int btusb_probe(struct usb_interface *intf,
@@ -1326,7 +1354,22 @@ static struct usb_driver btusb_driver = {
 	.disable_hub_initiated_lpm = 1,
 };
 
-module_usb_driver(btusb_driver);
+static int __init btusb_init(void)
+{
+	return usb_register(&btusb_driver);
+}
+
+static void __exit btusb_exit(void)
+{
+	int i;
+	for (i = 0; i < sizeof(firmware) / sizeof(firmware[0]); i++)
+		if (firmware[i].data)
+			kfree(firmware[i].data);
+	usb_deregister(&btusb_driver);
+}
+
+module_init(btusb_init);
+module_exit(btusb_exit);
 
 module_param(ignore_dga, bool, 0644);
 MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH 0/2] broadcom patchram firmware loader
  2012-08-14 14:24 [RFC][PATCH 0/2] broadcom patchram firmware loader Jesse Sung
  2012-08-14 14:24 ` [RFC][PATCH 1/2] Implement " Jesse Sung
  2012-08-14 14:24 ` [RFC][PATCH 2/2] Cache firmware images for later use Jesse Sung
@ 2012-08-14 17:14 ` Joao Paulo Rechi Vita
  2012-08-15  1:14   ` Jesse Sung
  2 siblings, 1 reply; 6+ messages in thread
From: Joao Paulo Rechi Vita @ 2012-08-14 17:14 UTC (permalink / raw)
  To: Jesse Sung; +Cc: linux-bluetooth

Hello Jesse,

On Tue, Aug 14, 2012 at 11:24 AM, Jesse Sung <jesse.sung@canonical.com> wrote:
>
> There is a user space firmware loading tool which can be found at
> http://article.gmane.org/gmane.linux.bluez.kernel/17932
>
> This tool requires hci device to do the firmware loading, but this
> may cause some race condition between patchram tool and bluetoothd
> or something that also works on hci interface.
>
> Also it needs some hooks to make firmware loads after bootup, s3,
> s4, rfkill, and device hotplug events. Implement this loader in kernel
> module would make things more easier.
>
>
> Wen-chien Jesse Sung (2):
>   Implement broadcom patchram firmware loader
>   Cache firmware images for later use
>

Can you please re-send the patches inline? This way it's easier for
people to comment on the mailing list and there is increased chance it
gets merged sooner. 'git send-email' is the best way to do that.

Thanks.

-- 
João Paulo Rechi Vita
Openbossa Labs - INdT

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH 0/2] broadcom patchram firmware loader
  2012-08-14 17:14 ` [RFC][PATCH 0/2] broadcom patchram firmware loader Joao Paulo Rechi Vita
@ 2012-08-15  1:14   ` Jesse Sung
  0 siblings, 0 replies; 6+ messages in thread
From: Jesse Sung @ 2012-08-15  1:14 UTC (permalink / raw)
  To: Joao Paulo Rechi Vita; +Cc: linux-bluetooth

Hi Joao,

Thanks for your reply. I'll send these patches again and make them inline.

Regards,
Jesse

2012/8/15 Joao Paulo Rechi Vita <jprvita@openbossa.org>:
> Hello Jesse,
>
> On Tue, Aug 14, 2012 at 11:24 AM, Jesse Sung <jesse.sung@canonical.com> wrote:
>>
>> There is a user space firmware loading tool which can be found at
>> http://article.gmane.org/gmane.linux.bluez.kernel/17932
>>
>> This tool requires hci device to do the firmware loading, but this
>> may cause some race condition between patchram tool and bluetoothd
>> or something that also works on hci interface.
>>
>> Also it needs some hooks to make firmware loads after bootup, s3,
>> s4, rfkill, and device hotplug events. Implement this loader in kernel
>> module would make things more easier.
>>
>>
>> Wen-chien Jesse Sung (2):
>>   Implement broadcom patchram firmware loader
>>   Cache firmware images for later use
>>
>
> Can you please re-send the patches inline? This way it's easier for
> people to comment on the mailing list and there is increased chance it
> gets merged sooner. 'git send-email' is the best way to do that.
>
> Thanks.
>
> --
> João Paulo Rechi Vita
> Openbossa Labs - INdT

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC][PATCH 0/2] broadcom patchram firmware loader
@ 2012-08-15  1:15 Jesse Sung
  0 siblings, 0 replies; 6+ messages in thread
From: Jesse Sung @ 2012-08-15  1:15 UTC (permalink / raw)
  To: linux-bluetooth

From: Wen-chien Jesse Sung <jesse.sung@canonical.com>

There is an user space firmware loading tool which can be found at
http://marc.info/?l=linux-bluetooth&m=132039175324993&w=2

This tool requires hci device to do the firmware loading, but this
may cause some race condition between patchram tool and bluetoothd
or something that also works on hci interface.

Also it needs some hooks to make firmware loads after bootup, s3,
s4, rfkill, and device hotplug events. Implement this loader in kernel
module would make things more easier.

Wen-chien Jesse Sung (2):
  Implement broadcom patchram firmware loader
  Cache firmware images for later use

 drivers/bluetooth/btusb.c |  154 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 147 insertions(+), 7 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2012-08-15  1:15 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-14 14:24 [RFC][PATCH 0/2] broadcom patchram firmware loader Jesse Sung
2012-08-14 14:24 ` [RFC][PATCH 1/2] Implement " Jesse Sung
2012-08-14 14:24 ` [RFC][PATCH 2/2] Cache firmware images for later use Jesse Sung
2012-08-14 17:14 ` [RFC][PATCH 0/2] broadcom patchram firmware loader Joao Paulo Rechi Vita
2012-08-15  1:14   ` Jesse Sung
  -- strict thread matches above, loose matches on Subject: below --
2012-08-15  1:15 Jesse Sung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).