From: Bala Shanmugam Date: Sun, 3 Oct 2010 15:00:02 +0000 (+0530) Subject: compat-wireless: Added ath3k sflash workaround to crap directory X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=8ede0d0830c9755ac9859e26ff80420aead55c36;p=openwrt%2Fstaging%2Fblogic.git compat-wireless: Added ath3k sflash workaround to crap directory This patch in crap directory enables btusb to load firmware to device RAM when it is plugged in. Reason for this not getting upstream: It was first rejected without any alternatives suggested. Then an alternative was finally suggested but too late for integration upstream. This is a work around until a new firmware and patch is being worked on which is acceptable upstream. For details refer to: http://lkml.org/lkml/2010/10/5/195 Signed-off-by: Bala Shanmugam --- 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 000000000000..87276c9662b9 --- /dev/null +++ b/crap/0003-btusb-Add-fw-load-support.patch @@ -0,0 +1,429 @@ +Reason for this not being merged upstream: + +It was first rejected without any alternatives suggested. Then +an alternative was finally suggested but too late for integration +upstream. + +This is a work around until a new firmware and patch is being worked +on which is acceptable upstream. + +For details refer to: + +http://lkml.org/lkml/2010/10/5/195 + +From 4ac276c14578b380d0c6a27658eeaa364efe6432 Mon Sep 17 00:00:00 2001 +From: Bala Shanmugam +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 + +--- + 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 + #include ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +