From: Bala Shanmugam <sbalashanmugam@atheros.com>
To: "Gustavo F. Padovan" <padovan@profusion.mobi>
Cc: Shanmugamkamatchi Balashanmugam
<Shanmugamkamatchi.Balashanmugam@Atheros.com>,
"linux-bluetooth@vger.kernel.org"
<linux-bluetooth@vger.kernel.org>
Subject: Re: [PATCH] Bluetooth: Add firmware support for Atheros 3012
Date: Fri, 11 Feb 2011 12:53:54 +0530 [thread overview]
Message-ID: <4D54E40A.4040203@atheros.com> (raw)
In-Reply-To: <20110210172611.GA20033@joana>
Hi Padovan,
On 2/10/2011 10:56 PM, Gustavo F. Padovan wrote:
> Hi Bala,
>
> * Bala Shanmugam<sbalashanmugam@atheros.com> [2011-02-09 17:45:15 +0530]:
>
>> Blacklisted AR3012 PID in btusb and added the same
>> in ath3k to load patch and sysconfig files.
>>
>> Signed-off-by: Bala Shanmugam<sbalashanmugam@atheros.com>
>> ---
>> drivers/bluetooth/ath3k.c | 326 ++++++++++++++++++++++++++++++++++++++++++++-
>> drivers/bluetooth/btusb.c | 3 +
>> 2 files changed, 325 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
>> index 41dadac..37e7cb4 100644
>> --- a/drivers/bluetooth/ath3k.c
>> +++ b/drivers/bluetooth/ath3k.c
>> @@ -31,6 +31,33 @@
>>
>> #define VERSION "1.0"
>>
>> +#define ATH3K_DNLOAD 0x01
>> +#define ATH3K_GETSTATE 0x05
>> +#define ATH3K_SET_NORMAL_MODE 0x07
>> +#define ATH3K_SET_PREBOOT_MODE 0x08
>> +#define ATH3K_GETVERSION 0x09
>> +#define USB_REG_SWITCH_VID_PID 0x0a
>> +
>> +#define ATH3K_MODE_MASK 0x3F
>> +#define ATH3K_NORMAL_MODE 0x0E
>> +#define ATH3K_PREBOOT_MODE 0x0D
>> +
>> +#define ATH3K_UPDATE_MASK 0xC0
>> +#define ATH3K_PATCH_UPDATE 0x80
>> +#define ATH3K_SYSCFG_UPDATE 0x40
>> +
>> +#define ATH3K_XTAL_FREQ_26M 0x00
>> +#define ATH3K_XTAL_FREQ_40M 0x01
>> +#define ATH3K_XTAL_FREQ_19P2 0x02
>> +#define ATH3K_NAME_LEN 0xFF
> There is some macros here that you are not using in the code.
For time being we don't support switching to preboot boot mode, so I didn't
use some macros. I will remove it now and add it when required.
>> +
>> +struct ath3k_version {
>> + unsigned int rom_version;
>> + unsigned int build_version;
>> + unsigned int ram_version;
>> + unsigned char ref_clock;
>> + unsigned char reserved[0x07];
>> +};
>>
>> static struct usb_device_id ath3k_table[] = {
>> /* Atheros AR3011 */
>> @@ -41,13 +68,29 @@ static struct usb_device_id ath3k_table[] = {
>>
>> /* Atheros AR9285 Malbec with sflash firmware */
>> { USB_DEVICE(0x03F0, 0x311D) },
>> +
>> + /* Atheros AR3012 with sflash firmware*/
>> + { USB_DEVICE(0x0CF3, 0x3004) },
>> +
>> { } /* Terminating entry */
>> };
>>
>> MODULE_DEVICE_TABLE(usb, ath3k_table);
>>
>> +#define BTUSB_ATH3012 0x80
>> +/* This table is to load patch and sysconfig files
>> + * for AR3012 */
>> +static struct usb_device_id ath3k_blist_tbl[] = {
>> +
>> + /* Atheros AR3012 with sflash firmware*/
>> + { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
>> +
>> + { } /* Terminating entry */
>> +};
>> +
>> #define USB_REQ_DFU_DNLOAD 1
>> #define BULK_SIZE 4096
>> +#define FW_HDR_SIZE 20
>>
>> static int ath3k_load_firmware(struct usb_device *udev,
>> const struct firmware *firmware)
>> @@ -67,10 +110,10 @@ static int ath3k_load_firmware(struct usb_device *udev,
>> }
>>
>> memcpy(send_buf, firmware->data, 20);
>> - if ((err = usb_control_msg(udev, pipe,
>> - USB_REQ_DFU_DNLOAD,
>> - USB_TYPE_VENDOR, 0, 0,
>> - send_buf, 20, USB_CTRL_SET_TIMEOUT))< 0) {
>> + err = usb_control_msg(udev, pipe, USB_REQ_DFU_DNLOAD,
>> + USB_TYPE_VENDOR, 0, 0,
>> + send_buf, 20, USB_CTRL_SET_TIMEOUT);
>> + if (err< 0) {
>> BT_ERR("Can't change to loading configuration err");
>> goto error;
>
> Please send a separate patch for code styling fixes.
Sure. Thanks.
>> }
>> @@ -103,6 +146,255 @@ error:
>> return err;
>> }
>>
>> +static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
>> +{
>> + int pipe = 0, ret;
>> +
>> + pipe = usb_rcvctrlpipe(udev, 0);
>> + ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE,
>> + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
>> + state, 0x01, USB_CTRL_SET_TIMEOUT);
>> + return ret;
>
> return usb_control_msg(); and get rid of ret.
Sure. Thanks.
>> +}
>> +
>> +static int ath3k_get_version(struct usb_device *udev,
>> + struct ath3k_version *version)
>> +{
>> + int pipe = 0, ret;
>> +
>> + pipe = usb_rcvctrlpipe(udev, 0);
>> + ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION,
>> + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
>> + sizeof(struct ath3k_version),
>> + USB_CTRL_SET_TIMEOUT);
>> + return ret;
> Same as above.
>
>> +}
>> +
>> +static int ath3k_load_fwfile(struct usb_device *udev,
>> + const struct firmware *firmware)
>> +{
>> + u8 *send_buf;
>> + int err, pipe, len, size, count, sent = 0;
>> + int ret;
>> +
>> + count = firmware->size;
>> +
>> + send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
>> + if (!send_buf) {
>> + BT_ERR("Can't allocate memory chunk for firmware");
>> + return -ENOMEM;
>> + }
>> +
>> + size = min_t(uint, count, FW_HDR_SIZE);
>> + memcpy(send_buf, firmware->data, size);
>> +
>> + pipe = usb_sndctrlpipe(udev, 0);
>> + ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD,
>> + USB_TYPE_VENDOR, 0, 0, send_buf,
>> + size, USB_CTRL_SET_TIMEOUT);
>> + if (ret< 0) {
>> + BT_ERR("Can't change to loading configuration err");
>> + kfree(send_buf);
>> + return ret;
>> + }
>> +
>> + sent += size;
>> + count -= size;
>> +
>> + while (count) {
>> + size = min_t(uint, count, BULK_SIZE);
>> + pipe = usb_sndbulkpipe(udev, 0x02);
>> +
>> + memcpy(send_buf, firmware->data + sent, size);
>> +
>> + err = usb_bulk_msg(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);
>> + kfree(send_buf);
>> + return err;
>> + }
>> + sent += size;
>> + count -= size;
>> + }
>> +
>> + kfree(send_buf);
>> + return 0;
>> +}
>> +
>> +static int ath3k_switch_pid(struct usb_device *udev)
>> +{
>> + int pipe = 0, ret;
>> +
>> + pipe = usb_sndctrlpipe(udev, 0);
>> + ret = usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID,
>> + USB_TYPE_VENDOR, 0, 0,
>> + NULL, 0, USB_CTRL_SET_TIMEOUT);
>> + return ret;
>> +}
>> +
>> +static int ath3k_set_normal_mode(struct usb_device *udev)
>> +{
>> + unsigned char fw_state;
>> + int pipe = 0, ret;
>> +
>> + ret = ath3k_get_state(udev,&fw_state);
>> + if (ret< 0) {
>> + BT_ERR("Can't get state to change to normal mode err");
>> + return ret;
>> + }
>> +
>> + if ((fw_state& ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
>> + BT_DBG("firmware was already in normal mode");
>> + return 0;
>> + }
>> +
>> + pipe = usb_sndctrlpipe(udev, 0);
>> + ret = usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE,
>> + USB_TYPE_VENDOR, 0, 0,
>> + NULL, 0, USB_CTRL_SET_TIMEOUT);
> Use return usb_control_msg(); here as well.
>
>> + if (ret< 0)
>> + BT_ERR("Can't set normal mode err");
>> +
>> + return ret;
>> +}
>> +
>> +static int ath3k_load_patch(struct usb_device *udev)
>> +{
>> + unsigned char fw_state;
>> + char filename[ATH3K_NAME_LEN] = {0};
>> + const struct firmware *firmware;
>> + struct ath3k_version fw_version, pt_version;
>> + int delay = 0, ret;
>> +
>> + ret = ath3k_get_state(udev,&fw_state);
>> + if (ret< 0) {
>> + BT_ERR("Can't get state to change to load ram patch err");
>> + return ret;
>> + }
>> +
>> + if (fw_state& ATH3K_PATCH_UPDATE) {
>> + BT_DBG("Patch was already downloaded");
>> + return 0;
>> + }
>> +
>> + ret = ath3k_get_version(udev,&fw_version);
>> + if (ret< 0) {
>> + BT_ERR("Can't get version to change to load ram patch err");
>> + return ret;
>> + }
>> +
>> + snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
>> + fw_version.rom_version);
>> +
>> + ret = request_firmware(&firmware, filename,&udev->dev);
>> + if (ret< 0) {
>> + BT_ERR("Patch file not found %s", filename);
>> + return ret;
>> + }
>> +
>> + pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
>> + pt_version.build_version = *(int *)
>> + (firmware->data + firmware->size - 4);
>> +
>> + if ((pt_version.rom_version != fw_version.rom_version) ||
>> + (pt_version.build_version<= fw_version.build_version)) {
>> + BT_ERR("Patch file version did not match with firmware");
>> + release_firmware(firmware);
>> + return -EINVAL;
>> + }
>> +
>> + ret = ath3k_load_fwfile(udev, firmware);
>> + if (ret< 0) {
>> + BT_ERR("Patch loading failed - %s", filename);
>> + release_firmware(firmware);
>> + return ret;
>> + }
>> +
>> + release_firmware(firmware);
>> +
>> + do {
>> + ret = ath3k_get_state(udev,&fw_state);
>> + if (ret< 0)
>> + continue;
>> +
>> + if (fw_state& ATH3K_PATCH_UPDATE) {
>> + BT_DBG("Patch has been downloaded successfully");
>> + break;
>> + }
>> + delay++;
>> + } while (delay< 3);
>> +
>> + return 0;
>> +}
>> +
>> +static int ath3k_load_syscfg(struct usb_device *udev)
>> +{
>> + unsigned char fw_state;
>> + char filename[ATH3K_NAME_LEN] = {0};
>> + const struct firmware *firmware;
>> + struct ath3k_version fw_version;
>> + int clk_value, delay = 0, ret;
>> +
>> + if (ath3k_get_state(udev,&fw_state)< 0) {
>> + BT_ERR("Can't get state to change to load configration err");
>> + return -EBUSY;
>> + }
>> +
>> + ret = ath3k_get_version(udev,&fw_version);
>> + if (ret< 0) {
>> + BT_ERR("Can't get version to change to load ram patch err");
>> + return ret;
>> + }
>> +
>> + switch (fw_version.ref_clock) {
>> +
>> + case ATH3K_XTAL_FREQ_26M:
>> + clk_value = 26;
>> + break;
>> + case ATH3K_XTAL_FREQ_40M:
>> + clk_value = 40;
>> + break;
>> + case ATH3K_XTAL_FREQ_19P2:
>> + clk_value = 19;
>> + break;
>> + default:
>> + clk_value = 0;
>> + break;
>> + }
>> +
>> + snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
>> + fw_version.rom_version, clk_value, ".dfu");
>> +
>> + ret = request_firmware(&firmware, filename,&udev->dev);
>> + if (ret< 0) {
>> + BT_ERR("Configuration file not found %s", filename);
>> + return ret;
>> + }
>> +
>> + ret = ath3k_load_fwfile(udev, firmware);
>> + if (ret< 0) {
>> + BT_ERR("Configuration loading failed - %s", filename);
>> + release_firmware(firmware);
>> + return ret;
>> + }
>> +
>> + release_firmware(firmware);
> ret = ath3k_load_fwfile()
> release_firmware()
> if (ret< 0)
> return ret;
>
>> +
>> + do {
>> + ret = ath3k_get_state(udev,&fw_state);
>> + if (ret< 0)
>> + continue;
> Can this became a infinite loop? if ath3k_get_state() always return ret< 0.
>
If the firmware download is successful, ath3k_get_state should not
return err.
We basically want to wait until the firmware state is updated.
I tested now and firmware state is updated immediately after download and
wait is not required I believe.
Thanks for pointing it out.
I will send updated patch incorporating all your comments.
Best Regards,
Bala.
prev parent reply other threads:[~2011-02-11 7:23 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-02-09 12:15 [PATCH] Bluetooth: Add firmware support for Atheros 3012 Bala Shanmugam
2011-02-10 17:26 ` Gustavo F. Padovan
2011-02-11 7:23 ` Bala Shanmugam [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4D54E40A.4040203@atheros.com \
--to=sbalashanmugam@atheros.com \
--cc=Shanmugamkamatchi.Balashanmugam@Atheros.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=padovan@profusion.mobi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).