2010-10-01 11:13:03

by Bala Shanmugam

[permalink] [raw]
Subject: [PATCH] Added firmware load patch to crap directory. This patch loads firmware from btusb when device is plugged in.

Disabled staging directory compilation for bt target.
Signed-off-by: Bala Shanmugam <[email protected]>
---
Makefile | 9 +-
crap/0003-btusb-Add-fw-load-support.patch | 424 +++++++++++++++++++++++++++++
2 files changed, 428 insertions(+), 5 deletions(-)
create mode 100644 crap/0003-btusb-Add-fw-load-support.patch

diff --git a/Makefile b/Makefile
index e2c594a..4505080 100644
--- a/Makefile
+++ b/Makefile
@@ -31,17 +31,16 @@ obj-$(CONFIG_COMPAT_NET_USB_MODULES) += drivers/net/usb/

obj-$(CONFIG_COMPAT_NETWORK_MODULES) += drivers/net/
obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/ssb/ drivers/misc/eeprom/
-endif
-
-obj-$(CONFIG_COMPAT_BLUETOOTH) += net/bluetooth/
-obj-$(CONFIG_COMPAT_BLUETOOTH_MODULES) += drivers/bluetooth/
-

ifeq ($(CONFIG_STAGING_EXCLUDE_BUILD),)
obj-$(CONFIG_COMPAT_STAGING) += drivers/staging/ath6kl/
obj-$(CONFIG_COMPAT_STAGING) += drivers/staging/brcm80211/
endif

+endif
+
+obj-$(CONFIG_COMPAT_BLUETOOTH) += net/bluetooth/
+obj-$(CONFIG_COMPAT_BLUETOOTH_MODULES) += drivers/bluetooth/

else

diff --git a/crap/0003-btusb-Add-fw-load-support.patch b/crap/0003-btusb-Add-fw-load-support.patch
new file mode 100644
index 0000000..2fc1abe
--- /dev/null
+++ b/crap/0003-btusb-Add-fw-load-support.patch
@@ -0,0 +1,424 @@
+Reason for not yet publishing: Marcel feels that Atheros sflash based BT device
+doesn't follow bluetooth H:2 specification and HCI commands should be supported
+in firmware if it is detected as bluetooth device. Using HCI command, firmware
+should be loaded.
+
+In sfash based device we don't have enough memory to support HCI commands in firmware.
+So load firmware from btusb when the device comes up.
+
+From 4ac276c14578b380d0c6a27658eeaa364efe6432 Mon Sep 17 00:00:00 2001
+From: Bala Shanmugam <[email protected]>
+Date: Fri, 1 Oct 2010 15:18:02 +0530
+Subject: [PATCH] Added support to load firmware to target RAM from btusb transport driver.
+ Each BT device vendor can add their product ID, firmware file, load and unload function
+ to btusb_fwcbs array. When the device is inserted btusb will call appropriate
+ firmware load function. This support will significantly reduce cost of
+ BT chip because of RAM based firmware.
+ Signed-off-by: Bala Shanmugam <[email protected]>
+
+---
+ drivers/bluetooth/Makefile | 1 +
+ drivers/bluetooth/btusb.c | 67 +++++++++++++++
+ drivers/bluetooth/fwload.c | 199 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/bluetooth/fwload.h | 39 +++++++++
+ 4 files changed, 306 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/bluetooth/fwload.c
+ create mode 100644 drivers/bluetooth/fwload.h
+
+diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
+index 71bdf13..5a55cbb 100644
+--- a/drivers/bluetooth/Makefile
++++ b/drivers/bluetooth/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
+ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
+
+ obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
++obj-$(CONFIG_BT_HCIBTUSB) += fwload.o
+ obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
+
+ obj-$(CONFIG_BT_ATH3K) += ath3k.o
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index d22ce3c..13e0fb8 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -34,6 +34,7 @@
+
+ #include <net/bluetooth/bluetooth.h>
+ #include <net/bluetooth/hci_core.h>
++#include "fwload.h"
+
+ #define VERSION "0.6"
+
+@@ -55,6 +56,26 @@ static struct usb_driver btusb_driver;
+ #define BTUSB_BROKEN_ISOC 0x20
+ #define BTUSB_WRONG_SCO_MTU 0x40
+
++static struct usb_device_id ath_table[] = {
++ /* Atheros AR3011 */
++ { USB_DEVICE(0x0CF3, 0x3002) },
++ { USB_DEVICE(0x13D3, 0x3304) },
++ { } /* Terminating entry */
++};
++
++/* Add firmware file, load and unload function
++ * to download the firmware to target RAM
++ */
++static struct fw_cb_config btusb_fwcbs[] = {
++ {
++ .fwfile = "ath3k-1.fw",
++ .usb_id_table = ath_table,
++ .fwload = ath_fw_load,
++ .fwunload = ath_fw_unload
++ },
++ {}
++};
++
+ static struct usb_device_id btusb_table[] = {
+ /* Generic Bluetooth USB device */
+ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+@@ -863,6 +884,7 @@ static int btusb_probe(struct usb_interface *intf,
+ struct btusb_data *data;
+ struct hci_dev *hdev;
+ int i, err;
++ const struct usb_device_id *match;
+
+ BT_DBG("intf %p id %p", intf, id);
+
+@@ -922,6 +944,19 @@ static int btusb_probe(struct usb_interface *intf,
+ data->udev = interface_to_usbdev(intf);
+ data->intf = intf;
+
++ for (i = 0; btusb_fwcbs[i].fwfile; i++) {
++ match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
++ if (match) {
++ if (btusb_fwcbs[i].fwload) {
++ btusb_fwcbs[i].data =
++ btusb_fwcbs[i].fwload(intf,
++ btusb_fwcbs[i].fwfile,
++ &btusb_fwcbs[i].bsuspend);
++ }
++ break;
++ }
++ }
++
+ spin_lock_init(&data->lock);
+
+ INIT_WORK(&data->work, btusb_work);
+@@ -1030,12 +1065,26 @@ static void btusb_disconnect(struct usb_interface *intf)
+ {
+ struct btusb_data *data = usb_get_intfdata(intf);
+ struct hci_dev *hdev;
++ const struct usb_device_id *match;
++ int i;
+
+ BT_DBG("intf %p", intf);
+
+ if (!data)
+ return;
+
++ for (i = 0; btusb_fwcbs[i].fwfile; i++) {
++ match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
++ if (match) {
++ if (btusb_fwcbs[i].fwunload) {
++ btusb_fwcbs[i].fwunload(btusb_fwcbs[i].data,
++ btusb_fwcbs[i].bsuspend);
++ btusb_fwcbs[i].data = NULL;
++ }
++ break;
++ }
++ }
++
+ hdev = data->hdev;
+
+ __hci_dev_hold(hdev);
+@@ -1061,12 +1110,22 @@ static void btusb_disconnect(struct usb_interface *intf)
+ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
+ {
+ struct btusb_data *data = usb_get_intfdata(intf);
++ const struct usb_device_id *match;
++ int i;
+
+ BT_DBG("intf %p", intf);
+
+ if (data->suspend_count++)
+ return 0;
+
++ for (i = 0; btusb_fwcbs[i].fwfile; i++) {
++ match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
++ if (match) {
++ btusb_fwcbs[i].bsuspend = 1;
++ break;
++ }
++ }
++
+ spin_lock_irq(&data->txlock);
+ if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
+ set_bit(BTUSB_SUSPENDING, &data->flags);
+@@ -1179,6 +1238,14 @@ static int __init btusb_init(void)
+
+ static void __exit btusb_exit(void)
+ {
++ int i;
++ for (i = 0; btusb_fwcbs[i].fwfile; i++) {
++ if (btusb_fwcbs[i].fwunload && btusb_fwcbs[i].data) {
++ btusb_fwcbs[i].fwunload(btusb_fwcbs[i].data,
++ btusb_fwcbs[i].bsuspend);
++ btusb_fwcbs[i].data = NULL;
++ }
++ }
+ usb_deregister(&btusb_driver);
+ }
+
+diff --git a/drivers/bluetooth/fwload.c b/drivers/bluetooth/fwload.c
+new file mode 100644
+index 0000000..a9a586a
+--- /dev/null
++++ b/drivers/bluetooth/fwload.c
+@@ -0,0 +1,199 @@
++/*
++ *
++ * Generic Bluetooth USB DFU driver to download firmware to target RAM
++ *
++ * Copyright (c) 2009-2010 Atheros Communications Inc.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/firmware.h>
++#include <linux/usb.h>
++#include <net/bluetooth/bluetooth.h>
++
++#define USB_REQ_DFU_DNLOAD 1
++#define USB_REQ_GET_STATE 5
++#define USB_FIRMWARE_RAM_MODE 11
++#define USB_FIRMWARE_FLASH_MODE 12
++#define BULK_SIZE 4096
++#define VERSION "1.0"
++
++struct firmware_data {
++ struct usb_device *udev;
++ u8 *fw_data;
++ u32 fw_size;
++ u32 fw_sent;
++};
++
++static int load_firmware(struct firmware_data *data,
++ unsigned char *firmware,
++ int count)
++{
++ u8 *send_buf;
++ int err, pipe, len, size, sent = 0;
++ char ucFirmware = 0;
++
++ BT_DBG("ath3k %p udev %p", data, data->udev);
++
++ if ((usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0),
++ USB_REQ_GET_STATE,
++ USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
++ &ucFirmware, 1, USB_CTRL_SET_TIMEOUT)) < 0) {
++ BT_ERR("Can't change to loading configuration err");
++ return -EBUSY;
++ }
++
++ if (ucFirmware == USB_FIRMWARE_RAM_MODE) {
++ /* RAM based firmware is available in the target.
++ * No need to load the firmware to RAM */
++ BT_DBG("RAM based firmware is available");
++ return 0;
++ }
++
++ pipe = usb_sndctrlpipe(data->udev, 0);
++ if ((usb_control_msg(data->udev, pipe,
++ USB_REQ_DFU_DNLOAD,
++ USB_TYPE_VENDOR, 0, 0,
++ firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
++ BT_ERR("Can't change to loading configuration err");
++ return -EBUSY;
++ }
++ sent += 20;
++ count -= 20;
++
++ send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
++ if (!send_buf) {
++ BT_ERR("Can't allocate memory chunk for firmware");
++ return -ENOMEM;
++ }
++
++ while (count) {
++ size = min_t(uint, count, BULK_SIZE);
++ pipe = usb_sndbulkpipe(data->udev, 0x02);
++ memcpy(send_buf, firmware + sent, size);
++
++ err = usb_bulk_msg(data->udev, pipe, send_buf, size,
++ &len, 3000);
++
++ if (err || (len != size)) {
++ BT_ERR("Error in firmware loading err = %d,"
++ "len = %d, size = %d", err, len, size);
++ goto error;
++ }
++
++ sent += size;
++ count -= size;
++ }
++
++ kfree(send_buf);
++ return 0;
++
++error:
++ kfree(send_buf);
++ return err;
++}
++
++void *ath_fw_load(struct usb_interface *intf,
++ const char *fwfile, bool *suspend)
++{
++ const struct firmware *firmware;
++ struct usb_device *udev = interface_to_usbdev(intf);
++ static struct firmware_data *data;
++ int size;
++
++ BT_DBG("\nintf %p suspend %d\n", intf, *suspend);
++
++ if (*suspend) {
++ load_firmware(data, data->fw_data, data->fw_size);
++ *suspend = 0;
++ return data;
++ }
++
++ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
++ return NULL;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return NULL;
++ data->udev = udev;
++
++ if (request_firmware(&firmware, fwfile, &udev->dev) < 0) {
++ kfree(data);
++ return NULL;
++ }
++
++ size = max_t(uint, firmware->size, 4096);
++ data->fw_data = kmalloc(size, GFP_KERNEL);
++ if (!data->fw_data) {
++ release_firmware(firmware);
++ kfree(data);
++ return NULL;
++ }
++
++ memcpy(data->fw_data, firmware->data, firmware->size);
++ data->fw_size = firmware->size;
++ data->fw_sent = 0;
++ release_firmware(firmware);
++
++ if (load_firmware(data, data->fw_data, data->fw_size)) {
++ kfree(data->fw_data);
++ kfree(data);
++ return NULL;
++ }
++ return data;
++}
++EXPORT_SYMBOL(ath_fw_load);
++
++void ath_fw_unload(void *pdata, bool bsuspend)
++{
++ struct firmware_data *data = (struct firmware_data *)pdata;
++
++ if (data == NULL)
++ return;
++
++ /* do not free the data on suspend as we will
++ * use it on resume */
++ if (!bsuspend) {
++ kfree(data->fw_data);
++ kfree(data);
++ }
++}
++EXPORT_SYMBOL(ath_fw_unload);
++
++static int __init fwload_init(void)
++{
++ BT_INFO("Firmware load driver init. Version:%s", VERSION);
++ return 0;
++}
++
++static void __exit fwload_deinit(void)
++{
++ BT_INFO("Firmware load driver deinit");
++}
++
++module_init(fwload_init);
++module_exit(fwload_deinit);
++
++MODULE_AUTHOR("Atheros Communications");
++MODULE_DESCRIPTION("Firmware load driver");
++MODULE_VERSION(VERSION);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/bluetooth/fwload.h b/drivers/bluetooth/fwload.h
+new file mode 100644
+index 0000000..5c1136a
+--- /dev/null
++++ b/drivers/bluetooth/fwload.h
+@@ -0,0 +1,39 @@
++/*
++ *
++ * Generic Bluetooth USB DFU driver to download firmware to target RAM
++ *
++ * Copyright (c) 2009-2010 Atheros Communications Inc.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#ifndef _FWLOAD_H_
++#define _FWLOAD_H_
++
++/* callbacks to load firmware to BT device RAM
++ * when it is inserted */
++struct fw_cb_config {
++ const char *fwfile;
++ void * (*fwload)(struct usb_interface *intf, const char *fwfile,
++ bool *bsuspend);
++ void (*fwunload)(void *, bool);
++ const struct usb_device_id *usb_id_table;
++ void *data;
++ bool bsuspend;
++};
++void *ath_fw_load(struct usb_interface *intf, const char *, bool *);
++void ath_fw_unload(void *pdata, bool bsuspend);
++
++#endif /* _FWLOAD_H_ */
+--
+1.6.3.3
+
--
1.6.3.3



2010-10-01 20:47:30

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH] Added firmware load patch to crap directory. This patch loads firmware from btusb when device is plugged in.

On Fri, Oct 1, 2010 at 4:12 AM, Bala Shanmugam
<[email protected]> wrote:
> Disabled staging directory compilation for bt target.

Huh? This commit log message also is unrelated to the patch below,
please separate and submit two separate patches.

> Signed-off-by: Bala Shanmugam <[email protected]>
> ---
>  Makefile                                  |    9 +-
>  crap/0003-btusb-Add-fw-load-support.patch |  424 +++++++++++++++++++++++++++++
>  2 files changed, 428 insertions(+), 5 deletions(-)
>  create mode 100644 crap/0003-btusb-Add-fw-load-support.patch
>
> diff --git a/Makefile b/Makefile
> index e2c594a..4505080 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -31,17 +31,16 @@ obj-$(CONFIG_COMPAT_NET_USB_MODULES) += drivers/net/usb/
>
>  obj-$(CONFIG_COMPAT_NETWORK_MODULES) += drivers/net/
>  obj-$(CONFIG_COMPAT_VAR_MODULES) +=  drivers/ssb/ drivers/misc/eeprom/
> -endif
> -
> -obj-$(CONFIG_COMPAT_BLUETOOTH) += net/bluetooth/
> -obj-$(CONFIG_COMPAT_BLUETOOTH_MODULES) += drivers/bluetooth/
> -
>
>  ifeq ($(CONFIG_STAGING_EXCLUDE_BUILD),)
>  obj-$(CONFIG_COMPAT_STAGING) += drivers/staging/ath6kl/
>  obj-$(CONFIG_COMPAT_STAGING) += drivers/staging/brcm80211/
>  endif
>
> +endif
> +
> +obj-$(CONFIG_COMPAT_BLUETOOTH) += net/bluetooth/
> +obj-$(CONFIG_COMPAT_BLUETOOTH_MODULES) += drivers/bluetooth/
>
>  else
>
> diff --git a/crap/0003-btusb-Add-fw-load-support.patch b/crap/0003-btusb-Add-fw-load-support.patch
> new file mode 100644
> index 0000000..2fc1abe
> --- /dev/null
> +++ b/crap/0003-btusb-Add-fw-load-support.patch

Actually I'd like to apply this patch to linux-next-pending/ not to
crap/ as you *did* post the patch upstream right? It just is not
getting applied yet for the reasons you stated.

> @@ -0,0 +1,424 @@
> +Reason for not yet publishing:

This not accurate, you did publish the patch, this goes into
linux-next-pending and you instead need a "Reason for not being merged
yet" or for adding it to the linux-next-pending/ directory.

> Marcel feels that Atheros sflash based BT device
> +doesn't follow bluetooth H:2 specification and HCI commands should be supported
> +in firmware if it is detected as bluetooth device. Using HCI command, firmware
> +should be loaded.
> +
> +In sfash based device we don't have enough memory to support HCI commands in firmware.
> +So load firmware from btusb when the device comes up.
> +

You should still ask the maintainer for an alternative, otherwise the
device unusable. Did you submit the patch first in [PATCH] form? If
not please submit the patch, all I saw as an RFC and no followup at
all.

2010-10-05 07:52:40

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Added firmware load patch to crap directory. This patch loads firmware from btusb when device is plugged in.

Hi Luis,

> > Marcel feels that Atheros sflash based BT device
> > +doesn't follow bluetooth H:2 specification and HCI commands should be supported
> > +in firmware if it is detected as bluetooth device. Using HCI command, firmware
> > +should be loaded.
> > +
> > +In sfash based device we don't have enough memory to support HCI commands in firmware.
> > +So load firmware from btusb when the device comes up.
> > +
>
> You should still ask the maintainer for an alternative, otherwise the
> device unusable. Did you submit the patch first in [PATCH] form? If
> not please submit the patch, all I saw as an RFC and no followup at
> all.

I think it is pretty clear how these devices should be designed when it
comes to firmware loading. Just having different USB PIDs for firmware
loading stage and fully functional Bluetooth device stage is not that
hard to do. Other companies have done this.

If you device claims Bluetooth USB class descriptors, then it should
behave like that and offer HCI protocol running on it.

Regards

Marcel