From 4541c561b6abeb52ad5d9428e4a23e037bbe2b49 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 5 May 2015 15:09:17 +0800 Subject: Bluetooth: btwilink: remove DEBUG define Remove the DEBUG define as the debug code; so can remove mass debug info from log buffer when using dmesg. Signed-off-by: Leo Yan Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btwilink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 55c135b7757a..7a722df97343 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#define DEBUG + #include #include #include -- cgit v1.2.3 From a1e85f04d8c73f885de1cca46515f66b82049231 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 21 Apr 2015 06:59:56 -0700 Subject: Bluetooth: btmrvl: fix compilation warning This patch fixes a compile warnning "dump_num maybe used uninitialized in this function". Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 01d6da577eeb..b9a811900f6a 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1217,7 +1217,7 @@ static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv) unsigned int reg, reg_start, reg_end; enum rdwr_status stat; u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr; - u8 dump_num, idx, i, read_reg, doneflag = 0; + u8 dump_num = 0, idx, i, read_reg, doneflag = 0; u32 memory_size, fw_dump_len = 0; /* dump sdio register first */ -- cgit v1.2.3 From db33c77dddc2ed2cff3061d0b096a9f5ab0c3647 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 14 May 2015 10:49:09 +0200 Subject: Bluetooth: btrtl: Create separate module for Realtek BT driver As already done for btintel and btbcm export setup as separate function in a vendor-specific module to hold all the Realtek specific commands. Signed-off-by: Carlo Caione Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 15 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btrtl.c | 390 +++++++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btrtl.h | 52 ++++++ drivers/bluetooth/btusb.c | 377 +------------------------------------------ 5 files changed, 462 insertions(+), 373 deletions(-) create mode 100644 drivers/bluetooth/btrtl.c create mode 100644 drivers/bluetooth/btrtl.h (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index ed5c2738bea2..2e777071e1dc 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -9,6 +9,10 @@ config BT_BCM tristate select FW_LOADER +config BT_RTL + tristate + select FW_LOADER + config BT_HCIBTUSB tristate "HCI USB driver" depends on USB @@ -32,6 +36,17 @@ config BT_HCIBTUSB_BCM Say Y here to compile support for Broadcom protocol. +config BT_HCIBTUSB_RTL + bool "Realtek protocol support" + depends on BT_HCIBTUSB + select BT_RTL + default y + help + The Realtek protocol support enables firmware and configuration + download support for Realtek Bluetooth controllers. + + Say Y here to compile support for Realtek protocol. + config BT_HCIBTSDIO tristate "HCI SDIO driver" depends on MMC diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index dd0d9c40b999..f40e194e7080 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o obj-$(CONFIG_BT_WILINK) += btwilink.o obj-$(CONFIG_BT_BCM) += btbcm.o +obj-$(CONFIG_BT_RTL) += btrtl.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c new file mode 100644 index 000000000000..84288938f7f2 --- /dev/null +++ b/drivers/bluetooth/btrtl.c @@ -0,0 +1,390 @@ +/* + * Bluetooth support for Realtek devices + * + * Copyright (C) 2015 Endless Mobile, 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. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "btrtl.h" + +#define VERSION "0.1" + +#define RTL_EPATCH_SIGNATURE "Realtech" +#define RTL_ROM_LMP_3499 0x3499 +#define RTL_ROM_LMP_8723A 0x1200 +#define RTL_ROM_LMP_8723B 0x8723 +#define RTL_ROM_LMP_8821A 0x8821 +#define RTL_ROM_LMP_8761A 0x8761 + +static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) +{ + struct rtl_rom_version_evt *rom_version; + struct sk_buff *skb; + + /* Read RTL ROM version command */ + skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Read ROM version failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*rom_version)) { + BT_ERR("%s: RTL version event length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + rom_version = (struct rtl_rom_version_evt *)skb->data; + BT_INFO("%s: rom_version status=%x version=%x", + hdev->name, rom_version->status, rom_version->version); + + *version = rom_version->version; + + kfree_skb(skb); + return 0; +} + +static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, + const struct firmware *fw, + unsigned char **_buf) +{ + const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; + struct rtl_epatch_header *epatch_info; + unsigned char *buf; + int i, ret, len; + size_t min_size; + u8 opcode, length, data, rom_version = 0; + int project_id = -1; + const unsigned char *fwptr, *chip_id_base; + const unsigned char *patch_length_base, *patch_offset_base; + u32 patch_offset = 0; + u16 patch_length, num_patches; + const u16 project_id_to_lmp_subver[] = { + RTL_ROM_LMP_8723A, + RTL_ROM_LMP_8723B, + RTL_ROM_LMP_8821A, + RTL_ROM_LMP_8761A + }; + + ret = rtl_read_rom_version(hdev, &rom_version); + if (ret) + return ret; + + min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; + if (fw->size < min_size) + return -EINVAL; + + fwptr = fw->data + fw->size - sizeof(extension_sig); + if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { + BT_ERR("%s: extension section signature mismatch", hdev->name); + return -EINVAL; + } + + /* Loop from the end of the firmware parsing instructions, until + * we find an instruction that identifies the "project ID" for the + * hardware supported by this firwmare file. + * Once we have that, we double-check that that project_id is suitable + * for the hardware we are working with. + */ + while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { + opcode = *--fwptr; + length = *--fwptr; + data = *--fwptr; + + BT_DBG("check op=%x len=%x data=%x", opcode, length, data); + + if (opcode == 0xff) /* EOF */ + break; + + if (length == 0) { + BT_ERR("%s: found instruction with length 0", + hdev->name); + return -EINVAL; + } + + if (opcode == 0 && length == 1) { + project_id = data; + break; + } + + fwptr -= length; + } + + if (project_id < 0) { + BT_ERR("%s: failed to find version instruction", hdev->name); + return -EINVAL; + } + + if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { + BT_ERR("%s: unknown project id %d", hdev->name, project_id); + return -EINVAL; + } + + if (lmp_subver != project_id_to_lmp_subver[project_id]) { + BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, + project_id_to_lmp_subver[project_id], lmp_subver); + return -EINVAL; + } + + epatch_info = (struct rtl_epatch_header *)fw->data; + if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { + BT_ERR("%s: bad EPATCH signature", hdev->name); + return -EINVAL; + } + + num_patches = le16_to_cpu(epatch_info->num_patches); + BT_DBG("fw_version=%x, num_patches=%d", + le32_to_cpu(epatch_info->fw_version), num_patches); + + /* After the rtl_epatch_header there is a funky patch metadata section. + * Assuming 2 patches, the layout is: + * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 + * + * Find the right patch for this chip. + */ + min_size += 8 * num_patches; + if (fw->size < min_size) + return -EINVAL; + + chip_id_base = fw->data + sizeof(struct rtl_epatch_header); + patch_length_base = chip_id_base + (sizeof(u16) * num_patches); + patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); + for (i = 0; i < num_patches; i++) { + u16 chip_id = get_unaligned_le16(chip_id_base + + (i * sizeof(u16))); + if (chip_id == rom_version + 1) { + patch_length = get_unaligned_le16(patch_length_base + + (i * sizeof(u16))); + patch_offset = get_unaligned_le32(patch_offset_base + + (i * sizeof(u32))); + break; + } + } + + if (!patch_offset) { + BT_ERR("%s: didn't find patch for chip id %d", + hdev->name, rom_version); + return -EINVAL; + } + + BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); + min_size = patch_offset + patch_length; + if (fw->size < min_size) + return -EINVAL; + + /* Copy the firmware into a new buffer and write the version at + * the end. + */ + len = patch_length; + buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); + + *_buf = buf; + return len; +} + +static int rtl_download_firmware(struct hci_dev *hdev, + const unsigned char *data, int fw_len) +{ + struct rtl_download_cmd *dl_cmd; + int frag_num = fw_len / RTL_FRAG_LEN + 1; + int frag_len = RTL_FRAG_LEN; + int ret = 0; + int i; + + dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); + if (!dl_cmd) + return -ENOMEM; + + for (i = 0; i < frag_num; i++) { + struct sk_buff *skb; + + BT_DBG("download fw (%d/%d)", i, frag_num); + + dl_cmd->index = i; + if (i == (frag_num - 1)) { + dl_cmd->index |= 0x80; /* data end */ + frag_len = fw_len % RTL_FRAG_LEN; + } + memcpy(dl_cmd->data, data, frag_len); + + /* Send download command */ + skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: download fw command failed (%ld)", + hdev->name, PTR_ERR(skb)); + ret = -PTR_ERR(skb); + goto out; + } + + if (skb->len != sizeof(struct rtl_download_response)) { + BT_ERR("%s: download fw event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto out; + } + + kfree_skb(skb); + data += RTL_FRAG_LEN; + } + +out: + kfree(dl_cmd); + return ret; +} + +static int btrtl_setup_rtl8723a(struct hci_dev *hdev) +{ + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name); + ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); + return ret; + } + + if (fw->size < 8) { + ret = -EINVAL; + goto out; + } + + /* Check that the firmware doesn't have the epatch signature + * (which is only for RTL8723B and newer). + */ + if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { + BT_ERR("%s: unexpected EPATCH signature!", hdev->name); + ret = -EINVAL; + goto out; + } + + ret = rtl_download_firmware(hdev, fw->data, fw->size); + +out: + release_firmware(fw); + return ret; +} + +static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, + const char *fw_name) +{ + unsigned char *fw_data = NULL; + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); + ret = request_firmware(&fw, fw_name, &hdev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load %s", hdev->name, fw_name); + return ret; + } + + ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); + if (ret < 0) + goto out; + + ret = rtl_download_firmware(hdev, fw_data, ret); + kfree(fw_data); + if (ret < 0) + goto out; + +out: + release_firmware(fw); + return ret; +} + +static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", + hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + +int btrtl_setup_realtek(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_local_version *resp; + u16 lmp_subver; + + skb = btrtl_read_local_version(hdev); + if (IS_ERR(skb)) + return -PTR_ERR(skb); + + resp = (struct hci_rp_read_local_version *)skb->data; + BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x " + "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev, + resp->lmp_ver, resp->lmp_subver); + + lmp_subver = le16_to_cpu(resp->lmp_subver); + kfree_skb(skb); + + /* Match a set of subver values that correspond to stock firmware, + * which is not compatible with standard btusb. + * If matched, upload an alternative firmware that does conform to + * standard btusb. Once that firmware is uploaded, the subver changes + * to a different value. + */ + switch (lmp_subver) { + case RTL_ROM_LMP_8723A: + case RTL_ROM_LMP_3499: + return btrtl_setup_rtl8723a(hdev); + case RTL_ROM_LMP_8723B: + return btrtl_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8723b_fw.bin"); + case RTL_ROM_LMP_8821A: + return btrtl_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8821a_fw.bin"); + case RTL_ROM_LMP_8761A: + return btrtl_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8761a_fw.bin"); + default: + BT_INFO("rtl: assuming no firmware upload needed."); + return 0; + } +} +EXPORT_SYMBOL_GPL(btrtl_setup_realtek); + +MODULE_AUTHOR("Daniel Drake "); +MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h new file mode 100644 index 000000000000..38ffe4890cd1 --- /dev/null +++ b/drivers/bluetooth/btrtl.h @@ -0,0 +1,52 @@ +/* + * Bluetooth support for Realtek devices + * + * Copyright (C) 2015 Endless Mobile, 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. + * + */ + +#define RTL_FRAG_LEN 252 + +struct rtl_download_cmd { + __u8 index; + __u8 data[RTL_FRAG_LEN]; +} __packed; + +struct rtl_download_response { + __u8 status; + __u8 index; +} __packed; + +struct rtl_rom_version_evt { + __u8 status; + __u8 version; +} __packed; + +struct rtl_epatch_header { + __u8 signature[8]; + __le32 fw_version; + __le16 num_patches; +} __packed; + +#if IS_ENABLED(CONFIG_BT_RTL) + +int btrtl_setup_realtek(struct hci_dev *hdev); + +#else + +static inline int btrtl_setup_realtek(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +#endif diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index d21f3b4176d3..df87016d18ab 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -31,6 +31,7 @@ #include "btintel.h" #include "btbcm.h" +#include "btrtl.h" #define VERSION "0.8" @@ -1369,378 +1370,6 @@ static int btusb_setup_csr(struct hci_dev *hdev) return ret; } -#define RTL_FRAG_LEN 252 - -struct rtl_download_cmd { - __u8 index; - __u8 data[RTL_FRAG_LEN]; -} __packed; - -struct rtl_download_response { - __u8 status; - __u8 index; -} __packed; - -struct rtl_rom_version_evt { - __u8 status; - __u8 version; -} __packed; - -struct rtl_epatch_header { - __u8 signature[8]; - __le32 fw_version; - __le16 num_patches; -} __packed; - -#define RTL_EPATCH_SIGNATURE "Realtech" -#define RTL_ROM_LMP_3499 0x3499 -#define RTL_ROM_LMP_8723A 0x1200 -#define RTL_ROM_LMP_8723B 0x8723 -#define RTL_ROM_LMP_8821A 0x8821 -#define RTL_ROM_LMP_8761A 0x8761 - -static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) -{ - struct rtl_rom_version_evt *rom_version; - struct sk_buff *skb; - int ret; - - /* Read RTL ROM version command */ - skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: Read ROM version failed (%ld)", - hdev->name, PTR_ERR(skb)); - return PTR_ERR(skb); - } - - if (skb->len != sizeof(*rom_version)) { - BT_ERR("%s: RTL version event length mismatch", hdev->name); - kfree_skb(skb); - return -EIO; - } - - rom_version = (struct rtl_rom_version_evt *)skb->data; - BT_INFO("%s: rom_version status=%x version=%x", - hdev->name, rom_version->status, rom_version->version); - - ret = rom_version->status; - if (ret == 0) - *version = rom_version->version; - - kfree_skb(skb); - return ret; -} - -static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, - const struct firmware *fw, - unsigned char **_buf) -{ - const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; - struct rtl_epatch_header *epatch_info; - unsigned char *buf; - int i, ret, len; - size_t min_size; - u8 opcode, length, data, rom_version = 0; - int project_id = -1; - const unsigned char *fwptr, *chip_id_base; - const unsigned char *patch_length_base, *patch_offset_base; - u32 patch_offset = 0; - u16 patch_length, num_patches; - const u16 project_id_to_lmp_subver[] = { - RTL_ROM_LMP_8723A, - RTL_ROM_LMP_8723B, - RTL_ROM_LMP_8821A, - RTL_ROM_LMP_8761A - }; - - ret = rtl_read_rom_version(hdev, &rom_version); - if (ret) - return -bt_to_errno(ret); - - min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; - if (fw->size < min_size) - return -EINVAL; - - fwptr = fw->data + fw->size - sizeof(extension_sig); - if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { - BT_ERR("%s: extension section signature mismatch", hdev->name); - return -EINVAL; - } - - /* Loop from the end of the firmware parsing instructions, until - * we find an instruction that identifies the "project ID" for the - * hardware supported by this firwmare file. - * Once we have that, we double-check that that project_id is suitable - * for the hardware we are working with. - */ - while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { - opcode = *--fwptr; - length = *--fwptr; - data = *--fwptr; - - BT_DBG("check op=%x len=%x data=%x", opcode, length, data); - - if (opcode == 0xff) /* EOF */ - break; - - if (length == 0) { - BT_ERR("%s: found instruction with length 0", - hdev->name); - return -EINVAL; - } - - if (opcode == 0 && length == 1) { - project_id = data; - break; - } - - fwptr -= length; - } - - if (project_id < 0) { - BT_ERR("%s: failed to find version instruction", hdev->name); - return -EINVAL; - } - - if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { - BT_ERR("%s: unknown project id %d", hdev->name, project_id); - return -EINVAL; - } - - if (lmp_subver != project_id_to_lmp_subver[project_id]) { - BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, - project_id_to_lmp_subver[project_id], lmp_subver); - return -EINVAL; - } - - epatch_info = (struct rtl_epatch_header *)fw->data; - if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { - BT_ERR("%s: bad EPATCH signature", hdev->name); - return -EINVAL; - } - - num_patches = le16_to_cpu(epatch_info->num_patches); - BT_DBG("fw_version=%x, num_patches=%d", - le32_to_cpu(epatch_info->fw_version), num_patches); - - /* After the rtl_epatch_header there is a funky patch metadata section. - * Assuming 2 patches, the layout is: - * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 - * - * Find the right patch for this chip. - */ - min_size += 8 * num_patches; - if (fw->size < min_size) - return -EINVAL; - - chip_id_base = fw->data + sizeof(struct rtl_epatch_header); - patch_length_base = chip_id_base + (sizeof(u16) * num_patches); - patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); - for (i = 0; i < num_patches; i++) { - u16 chip_id = get_unaligned_le16(chip_id_base + - (i * sizeof(u16))); - if (chip_id == rom_version + 1) { - patch_length = get_unaligned_le16(patch_length_base + - (i * sizeof(u16))); - patch_offset = get_unaligned_le32(patch_offset_base + - (i * sizeof(u32))); - break; - } - } - - if (!patch_offset) { - BT_ERR("%s: didn't find patch for chip id %d", - hdev->name, rom_version); - return -EINVAL; - } - - BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); - min_size = patch_offset + patch_length; - if (fw->size < min_size) - return -EINVAL; - - /* Copy the firmware into a new buffer and write the version at - * the end. - */ - len = patch_length; - buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); - - *_buf = buf; - return len; -} - -static int rtl_download_firmware(struct hci_dev *hdev, - const unsigned char *data, int fw_len) -{ - struct rtl_download_cmd *dl_cmd; - int frag_num = fw_len / RTL_FRAG_LEN + 1; - int frag_len = RTL_FRAG_LEN; - int ret = 0; - int i; - - dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); - if (!dl_cmd) - return -ENOMEM; - - for (i = 0; i < frag_num; i++) { - struct rtl_download_response *dl_resp; - struct sk_buff *skb; - - BT_DBG("download fw (%d/%d)", i, frag_num); - - dl_cmd->index = i; - if (i == (frag_num - 1)) { - dl_cmd->index |= 0x80; /* data end */ - frag_len = fw_len % RTL_FRAG_LEN; - } - memcpy(dl_cmd->data, data, frag_len); - - /* Send download command */ - skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: download fw command failed (%ld)", - hdev->name, PTR_ERR(skb)); - ret = -PTR_ERR(skb); - goto out; - } - - if (skb->len != sizeof(*dl_resp)) { - BT_ERR("%s: download fw event length mismatch", - hdev->name); - kfree_skb(skb); - ret = -EIO; - goto out; - } - - dl_resp = (struct rtl_download_response *)skb->data; - if (dl_resp->status != 0) { - kfree_skb(skb); - ret = bt_to_errno(dl_resp->status); - goto out; - } - - kfree_skb(skb); - data += RTL_FRAG_LEN; - } - -out: - kfree(dl_cmd); - return ret; -} - -static int btusb_setup_rtl8723a(struct hci_dev *hdev) -{ - struct btusb_data *data = dev_get_drvdata(&hdev->dev); - struct usb_device *udev = interface_to_usbdev(data->intf); - const struct firmware *fw; - int ret; - - BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name); - ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev); - if (ret < 0) { - BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); - return ret; - } - - if (fw->size < 8) { - ret = -EINVAL; - goto out; - } - - /* Check that the firmware doesn't have the epatch signature - * (which is only for RTL8723B and newer). - */ - if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { - BT_ERR("%s: unexpected EPATCH signature!", hdev->name); - ret = -EINVAL; - goto out; - } - - ret = rtl_download_firmware(hdev, fw->data, fw->size); - -out: - release_firmware(fw); - return ret; -} - -static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, - const char *fw_name) -{ - struct btusb_data *data = dev_get_drvdata(&hdev->dev); - struct usb_device *udev = interface_to_usbdev(data->intf); - unsigned char *fw_data = NULL; - const struct firmware *fw; - int ret; - - BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); - ret = request_firmware(&fw, fw_name, &udev->dev); - if (ret < 0) { - BT_ERR("%s: Failed to load %s", hdev->name, fw_name); - return ret; - } - - ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); - if (ret < 0) - goto out; - - ret = rtl_download_firmware(hdev, fw_data, ret); - kfree(fw_data); - if (ret < 0) - goto out; - -out: - release_firmware(fw); - return ret; -} - -static int btusb_setup_realtek(struct hci_dev *hdev) -{ - struct sk_buff *skb; - struct hci_rp_read_local_version *resp; - u16 lmp_subver; - - skb = btusb_read_local_version(hdev); - if (IS_ERR(skb)) - return -PTR_ERR(skb); - - resp = (struct hci_rp_read_local_version *)skb->data; - BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x " - "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev, - resp->lmp_ver, resp->lmp_subver); - - lmp_subver = le16_to_cpu(resp->lmp_subver); - kfree_skb(skb); - - /* Match a set of subver values that correspond to stock firmware, - * which is not compatible with standard btusb. - * If matched, upload an alternative firmware that does conform to - * standard btusb. Once that firmware is uploaded, the subver changes - * to a different value. - */ - switch (lmp_subver) { - case RTL_ROM_LMP_8723A: - case RTL_ROM_LMP_3499: - return btusb_setup_rtl8723a(hdev); - case RTL_ROM_LMP_8723B: - return btusb_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8723b_fw.bin"); - case RTL_ROM_LMP_8821A: - return btusb_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8821a_fw.bin"); - case RTL_ROM_LMP_8761A: - return btusb_setup_rtl8723b(hdev, lmp_subver, - "rtl_bt/rtl8761a_fw.bin"); - default: - BT_INFO("rtl: assuming no firmware upload needed."); - return 0; - } -} - static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, struct intel_version *ver) { @@ -3172,8 +2801,10 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_bdaddr = btusb_set_bdaddr_ath3012; } +#ifdef CONFIG_BT_HCIBTUSB_RTL if (id->driver_info & BTUSB_REALTEK) - hdev->setup = btusb_setup_realtek; + hdev->setup = btrtl_setup_realtek; +#endif if (id->driver_info & BTUSB_AMP) { /* AMP controllers do not support SCO packets */ -- cgit v1.2.3 From 5e13441ca413f5a8d04601d675accb35d37c6b08 Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Fri, 15 May 2015 11:58:40 +0200 Subject: Bluetooth: btusb: Fix calls to __hci_cmd_sync() Remove test of command reply status as it is already performed by __hci_cmd_sync(). __hci_cmd_sync_ev() function already returns an error if it got a non-zero status either through a Command Complete or a Command Status event. For both of these events the status is collected up in the event handlers called by hci_event_packet() and then passed as the second parameter to req_complete_skb(). The req_complete_skb() callback in turn is hci_req_sync_complete() for __hci_cmd_sync_ev() which stores the status in hdev->req_result. The hdev->req_result is then further converted through bt_to_errno() back in __hci_cmd_sync_ev(). Signed-off-by: Frederic Danis Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index df87016d18ab..b9f282112153 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1577,12 +1577,6 @@ static int btusb_setup_intel(struct hci_dev *hdev) } ver = (struct intel_version *)skb->data; - if (ver->status) { - BT_ERR("%s Intel fw version event failed (%02x)", hdev->name, - ver->status); - kfree_skb(skb); - return -bt_to_errno(ver->status); - } BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x", hdev->name, ver->hw_platform, ver->hw_variant, @@ -1630,15 +1624,6 @@ static int btusb_setup_intel(struct hci_dev *hdev) return PTR_ERR(skb); } - if (skb->data[0]) { - u8 evt_status = skb->data[0]; - - BT_ERR("%s enable Intel manufacturer mode event failed (%02x)", - hdev->name, evt_status); - kfree_skb(skb); - release_firmware(fw); - return -bt_to_errno(evt_status); - } kfree_skb(skb); disable_patch = 1; @@ -1984,13 +1969,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) } ver = (struct intel_version *)skb->data; - if (ver->status) { - BT_ERR("%s: Intel version command failure (%02x)", - hdev->name, ver->status); - err = -bt_to_errno(ver->status); - kfree_skb(skb); - return err; - } /* The hardware platform number has a fixed value of 0x37 and * for now only accept this single value. @@ -2065,13 +2043,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) } params = (struct intel_boot_params *)skb->data; - if (params->status) { - BT_ERR("%s: Intel boot parameters command failure (%02x)", - hdev->name, params->status); - err = -bt_to_errno(params->status); - kfree_skb(skb); - return err; - } BT_INFO("%s: Device revision is %u", hdev->name, le16_to_cpu(params->dev_revid)); @@ -2304,13 +2275,6 @@ static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code) return; } - if (skb->data[0] != 0x00) { - BT_ERR("%s: Exception info command failure (%02x)", - hdev->name, skb->data[0]); - kfree_skb(skb); - return; - } - BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); kfree_skb(skb); -- cgit v1.2.3 From b1f5cf0cae090dae9ac045670fec2d0c5253592a Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Fri, 15 May 2015 11:58:41 +0200 Subject: Bluetooth: btintel: Fix calls to __hci_cmd_sync() Remove test of command reply status as it is already performed by __hci_cmd_sync(). __hci_cmd_sync_ev() function already returns an error if it got a non-zero status either through a Command Complete or a Command Status event. For both of these events the status is collected up in the event handlers called by hci_event_packet() and then passed as the second parameter to req_complete_skb(). The req_complete_skb() callback in turn is hci_req_sync_complete() for __hci_cmd_sync_ev() which stores the status in hdev->req_result. The hdev->req_result is then further converted through bt_to_errno() back in __hci_cmd_sync_ev(). Signed-off-by: Frederic Danis Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btintel.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 2d43d4279b00..828f2f8d1568 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -53,12 +53,6 @@ int btintel_check_bdaddr(struct hci_dev *hdev) } bda = (struct hci_rp_read_bd_addr *)skb->data; - if (bda->status) { - BT_ERR("%s: Intel device address result failed (%02x)", - hdev->name, bda->status); - kfree_skb(skb); - return -bt_to_errno(bda->status); - } /* For some Intel based controllers, the default Bluetooth device * address 00:03:19:9E:8B:00 can be found. These controllers are -- cgit v1.2.3 From 43b79209b5be533173eea08535558cf517b334ca Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Fri, 15 May 2015 11:58:42 +0200 Subject: Bluetooth: btbcm: Fix calls to __hci_cmd_sync() Remove test of command reply status as it is already performed by __hci_cmd_sync(). __hci_cmd_sync_ev() function already returns an error if it got a non-zero status either through a Command Complete or a Command Status event. For both of these events the status is collected up in the event handlers called by hci_event_packet() and then passed as the second parameter to req_complete_skb(). The req_complete_skb() callback in turn is hci_req_sync_complete() for __hci_cmd_sync_ev() which stores the status in hdev->req_result. The hdev->req_result is then further converted through bt_to_errno() back in __hci_cmd_sync_ev(). Signed-off-by: Frederic Danis Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btbcm.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 4bba86677adc..728fce38a5a2 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -55,12 +55,6 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) } bda = (struct hci_rp_read_bd_addr *)skb->data; - if (bda->status) { - BT_ERR("%s: BCM: Device address result failed (%02x)", - hdev->name, bda->status); - kfree_skb(skb); - return -bt_to_errno(bda->status); - } /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller * with no configured address. -- cgit v1.2.3 From 1a19cb680be0d4b06ce9a9d6516b8f45f544d3e8 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:39 +0200 Subject: ieee802154: change transmit power to s32 This patch change the transmit power from s8 to s32. This prepares to store a mbm value instead dbm inside the transmit power variable. The old interface keep the a s8 dbm value, which should be backward compatibility when assign s8 to s32. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 67d00fbc2e0e..02b6bb72304d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1194,7 +1194,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, } static int -at86rf230_set_txpower(struct ieee802154_hw *hw, s8 db) +at86rf230_set_txpower(struct ieee802154_hw *hw, s32 db) { struct at86rf230_local *lp = hw->priv; -- cgit v1.2.3 From e2eb173aaacd1a1bcd255d3e74ffb719e47eeadb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:40 +0200 Subject: ieee802154: change transmit power to mbm This patch change the handling of transmit power level from dbm to mbm. This prepares to handle floating point transmit power levels values. The old netlink 802.15.4 will convert the dbm value to mbm for handling backward compatibility. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 02b6bb72304d..3a303e4a3c07 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1194,9 +1194,10 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, } static int -at86rf230_set_txpower(struct ieee802154_hw *hw, s32 db) +at86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm) { struct at86rf230_local *lp = hw->priv; + s8 db = mbm / 100; /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five * bits decrease power in 1dB steps. 0x60 represents extra PA gain of -- cgit v1.2.3 From 32b23550ad64d9676f2218b3d5de46bacf98ef1d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:41 +0200 Subject: ieee802154: change cca ed level to mbm This patch change the handling of cca energy detection level from dbm to mbm. This prepares to handle floating point cca energy detection levels values. The old netlink 802.15.4 will convert the dbm value to mbm for handling backward compatibility. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 3a303e4a3c07..e68d45ed622e 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1268,9 +1268,10 @@ at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level) } static int -at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 level) +at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) { struct at86rf230_local *lp = hw->priv; + s32 level = mbm / 100; if (level < lp->data->rssi_base_val || level > 30) return -EINVAL; -- cgit v1.2.3 From 72f655e44db9c7e835ceba96dc03cbe979d3f80d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:42 +0200 Subject: ieee802154: introduce wpan_phy_supported This patch introduce the wpan_phy_supported struct for wpan_phy. There is currently no way to check if a transceiver can handle IEEE 802.15.4 complaint values. With this struct we can check before if the transceiver supports these values before sending to driver layer. Signed-off-by: Alexander Aring Suggested-by: Phoebe Buckheister Acked-by: Varka Bhadram Cc: Alan Ott Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 8 ++++---- drivers/net/ieee802154/cc2520.c | 2 +- drivers/net/ieee802154/fakelb.c | 30 +++++++++++++++--------------- drivers/net/ieee802154/mrf24j40.c | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index e68d45ed622e..151d57f4320d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1579,7 +1579,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) case 3: chip = "at86rf231"; lp->data = &at86rf231_data; - lp->hw->phy->channels_supported[0] = 0x7FFF800; + lp->hw->phy->supported.channels[0] = 0x7FFF800; lp->hw->phy->current_channel = 11; lp->hw->phy->symbol_duration = 16; break; @@ -1587,15 +1587,15 @@ at86rf230_detect_device(struct at86rf230_local *lp) chip = "at86rf212"; lp->data = &at86rf212_data; lp->hw->flags |= IEEE802154_HW_LBT; - lp->hw->phy->channels_supported[0] = 0x00007FF; - lp->hw->phy->channels_supported[2] = 0x00007FF; + lp->hw->phy->supported.channels[0] = 0x00007FF; + lp->hw->phy->supported.channels[2] = 0x00007FF; lp->hw->phy->current_channel = 5; lp->hw->phy->symbol_duration = 25; break; case 11: chip = "at86rf233"; lp->data = &at86rf233_data; - lp->hw->phy->channels_supported[0] = 0x7FFF800; + lp->hw->phy->supported.channels[0] = 0x7FFF800; lp->hw->phy->current_channel = 13; lp->hw->phy->symbol_duration = 16; break; diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index f833b8bb6663..84b28a05c5a1 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -653,7 +653,7 @@ static int cc2520_register(struct cc2520_private *priv) ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr); /* We do support only 2.4 Ghz */ - priv->hw->phy->channels_supported[0] = 0x7FFF800; + priv->hw->phy->supported.channels[0] = 0x7FFF800; priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_AFILT; diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index dc2bfb600b4b..91bbf030a443 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -149,35 +149,35 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) priv->hw = hw; /* 868 MHz BPSK 802.15.4-2003 */ - hw->phy->channels_supported[0] |= 1; + hw->phy->supported.channels[0] |= 1; /* 915 MHz BPSK 802.15.4-2003 */ - hw->phy->channels_supported[0] |= 0x7fe; + hw->phy->supported.channels[0] |= 0x7fe; /* 2.4 GHz O-QPSK 802.15.4-2003 */ - hw->phy->channels_supported[0] |= 0x7FFF800; + hw->phy->supported.channels[0] |= 0x7FFF800; /* 868 MHz ASK 802.15.4-2006 */ - hw->phy->channels_supported[1] |= 1; + hw->phy->supported.channels[1] |= 1; /* 915 MHz ASK 802.15.4-2006 */ - hw->phy->channels_supported[1] |= 0x7fe; + hw->phy->supported.channels[1] |= 0x7fe; /* 868 MHz O-QPSK 802.15.4-2006 */ - hw->phy->channels_supported[2] |= 1; + hw->phy->supported.channels[2] |= 1; /* 915 MHz O-QPSK 802.15.4-2006 */ - hw->phy->channels_supported[2] |= 0x7fe; + hw->phy->supported.channels[2] |= 0x7fe; /* 2.4 GHz CSS 802.15.4a-2007 */ - hw->phy->channels_supported[3] |= 0x3fff; + hw->phy->supported.channels[3] |= 0x3fff; /* UWB Sub-gigahertz 802.15.4a-2007 */ - hw->phy->channels_supported[4] |= 1; + hw->phy->supported.channels[4] |= 1; /* UWB Low band 802.15.4a-2007 */ - hw->phy->channels_supported[4] |= 0x1e; + hw->phy->supported.channels[4] |= 0x1e; /* UWB High band 802.15.4a-2007 */ - hw->phy->channels_supported[4] |= 0xffe0; + hw->phy->supported.channels[4] |= 0xffe0; /* 750 MHz O-QPSK 802.15.4c-2009 */ - hw->phy->channels_supported[5] |= 0xf; + hw->phy->supported.channels[5] |= 0xf; /* 750 MHz MPSK 802.15.4c-2009 */ - hw->phy->channels_supported[5] |= 0xf0; + hw->phy->supported.channels[5] |= 0xf0; /* 950 MHz BPSK 802.15.4d-2009 */ - hw->phy->channels_supported[6] |= 0x3ff; + hw->phy->supported.channels[6] |= 0x3ff; /* 950 MHz GFSK 802.15.4d-2009 */ - hw->phy->channels_supported[6] |= 0x3ffc00; + hw->phy->supported.channels[6] |= 0x3ffc00; INIT_LIST_HEAD(&priv->list); priv->fake = fake; diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index fba2dfd910f7..f2a1bd122a74 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -750,7 +750,7 @@ static int mrf24j40_probe(struct spi_device *spi) devrec->hw->priv = devrec; devrec->hw->parent = &devrec->spi->dev; - devrec->hw->phy->channels_supported[0] = CHANNEL_MASK; + devrec->hw->phy->supported.channels[0] = CHANNEL_MASK; devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_AFILT; -- cgit v1.2.3 From edea8f7c75ec6c238130bd7e74d9f6f4c26e97b0 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:46 +0200 Subject: cfg802154: introduce wpan phy flags This patch introduce a flag property for the wpan phy structure. The current flag settings in ieee802154_hw are accessable in mac802154 layer only which is okay for flags which indicates MAC handling which are done by phy. For real PHY layer settings like cca mode, transmit power, cca energy detection level. The difference between these flags are that the MAC handling flags are only handled in mac802154/HardMac layer e.g. on an interface up. The phy settings are direct netlink calls from nl802154 into the driver layer and the nl802154 need to have a chance to check if the driver supports this handling before sending to the next layer. We also check now on PHY flags while dumping and setting pib attributes. In comparing with MIB attributes the 802.15.4 gives us an default value which we assume when a transceiver implement less functionality. In case of MIB settings the nl802154 layer doesn't need to check on the ieee802154_hw flags then. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 151d57f4320d..b0ffd1cd0010 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1566,8 +1566,13 @@ at86rf230_detect_device(struct at86rf230_local *lp) } lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET | - IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; + IEEE802154_HW_CSMA_PARAMS | + IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT | + IEEE802154_HW_PROMISCUOUS; + + lp->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | + WPAN_PHY_FLAG_CCA_ED_LEVEL | + WPAN_PHY_FLAG_CCA_MODE; lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; -- cgit v1.2.3 From 8377d22c0385b4a08ddeb1029b80674eb5db38b4 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:48 +0200 Subject: at86rf230: set cca_modes supported flags This patch sets the at86rf230 supported cca modes. In case of at86rf212 it also can support listen before transmit. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index b0ffd1cd0010..fabde3ac49b3 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1574,6 +1574,11 @@ at86rf230_detect_device(struct at86rf230_local *lp) WPAN_PHY_FLAG_CCA_ED_LEVEL | WPAN_PHY_FLAG_CCA_MODE; + lp->hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) | + BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER); + lp->hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) | + BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR); + lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; switch (part) { @@ -1596,6 +1601,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->supported.channels[2] = 0x00007FF; lp->hw->phy->current_channel = 5; lp->hw->phy->symbol_duration = 25; + lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH; break; case 11: chip = "at86rf233"; -- cgit v1.2.3 From 6f4da3f897906d0e1f27e3e44bd445f8e6d7bd85 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:49 +0200 Subject: at86rf230: rework tx power support This patch adds support for get transmit power levels and reworks the set of transmit power levels which was broken before. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 83 +++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index fabde3ac49b3..dff7e47f5afb 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -51,6 +51,7 @@ struct at86rf2xx_chip_data { int (*set_channel)(struct at86rf230_local *, u8, u8); int (*get_desense_steps)(struct at86rf230_local *, s32); + int (*set_txpower)(struct at86rf230_local *, s32); }; #define AT86RF2XX_MAX_BUF (127 + 3) @@ -124,9 +125,12 @@ struct at86rf230_local { #define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 #define SR_PA_EXT_EN 0x04, 0x80, 7 #define RG_PHY_TX_PWR (0x05) -#define SR_TX_PWR 0x05, 0x0f, 0 -#define SR_PA_LT 0x05, 0x30, 4 -#define SR_PA_BUF_LT 0x05, 0xc0, 6 +#define SR_TX_PWR_23X 0x05, 0x0f, 0 +#define SR_PA_LT_230 0x05, 0x30, 4 +#define SR_PA_BUF_LT_230 0x05, 0xc0, 6 +#define SR_TX_PWR_212 0x05, 0x1f, 0 +#define SR_GC_PA_212 0x05, 0x60, 5 +#define SR_PA_BOOST_LT_212 0x05, 0x80, 7 #define RG_PHY_RSSI (0x06) #define SR_RSSI 0x06, 0x1f, 0 #define SR_RND_VALUE 0x06, 0x60, 5 @@ -1193,24 +1197,56 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, return 0; } +#define AT86RF23X_MAX_TX_POWERS 0xF +static const s32 at86rf233_powers[AT86RF23X_MAX_TX_POWERS + 1] = { + 400, 370, 340, 300, 250, 200, 100, 0, -100, -200, -300, -400, -600, + -800, -1200, -1700, +}; + +static const s32 at86rf231_powers[AT86RF23X_MAX_TX_POWERS + 1] = { + 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700, + -900, -1200, -1700, +}; + +#define AT86RF212_MAX_TX_POWERS 0x1F +static const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = { + 500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700, + -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700, + -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600, +}; + static int -at86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm) +at86rf23x_set_txpower(struct at86rf230_local *lp, s32 mbm) { - struct at86rf230_local *lp = hw->priv; - s8 db = mbm / 100; + u32 i; - /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five - * bits decrease power in 1dB steps. 0x60 represents extra PA gain of - * 0dB. - * thus, supported values for db range from -26 to 5, for 31dB of - * reduction to 0dB of reduction. - */ - if (db > 5 || db < -26) - return -EINVAL; + for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) { + if (lp->hw->phy->supported.tx_powers[i] == mbm) + return at86rf230_write_subreg(lp, SR_TX_PWR_23X, i); + } + + return -EINVAL; +} + +static int +at86rf212_set_txpower(struct at86rf230_local *lp, s32 mbm) +{ + u32 i; + + for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) { + if (lp->hw->phy->supported.tx_powers[i] == mbm) + return at86rf230_write_subreg(lp, SR_TX_PWR_212, i); + } - db = -(db - 5); + return -EINVAL; +} + +static int +at86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm) +{ + struct at86rf230_local *lp = hw->priv; - return __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db); + return lp->data->set_txpower(lp, mbm); } static int @@ -1367,7 +1403,8 @@ static struct at86rf2xx_chip_data at86rf233_data = { .t_p_ack = 545, .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, - .get_desense_steps = at86rf23x_get_desens_steps + .get_desense_steps = at86rf23x_get_desens_steps, + .set_txpower = at86rf23x_set_txpower, }; static struct at86rf2xx_chip_data at86rf231_data = { @@ -1380,7 +1417,8 @@ static struct at86rf2xx_chip_data at86rf231_data = { .t_p_ack = 545, .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, - .get_desense_steps = at86rf23x_get_desens_steps + .get_desense_steps = at86rf23x_get_desens_steps, + .set_txpower = at86rf23x_set_txpower, }; static struct at86rf2xx_chip_data at86rf212_data = { @@ -1393,7 +1431,8 @@ static struct at86rf2xx_chip_data at86rf212_data = { .t_p_ack = 545, .rssi_base_val = -100, .set_channel = at86rf212_set_channel, - .get_desense_steps = at86rf212_get_desens_steps + .get_desense_steps = at86rf212_get_desens_steps, + .set_txpower = at86rf212_set_txpower, }; static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim) @@ -1592,6 +1631,8 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->supported.channels[0] = 0x7FFF800; lp->hw->phy->current_channel = 11; lp->hw->phy->symbol_duration = 16; + lp->hw->phy->supported.tx_powers = at86rf231_powers; + lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf231_powers); break; case 7: chip = "at86rf212"; @@ -1602,6 +1643,8 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->current_channel = 5; lp->hw->phy->symbol_duration = 25; lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH; + lp->hw->phy->supported.tx_powers = at86rf212_powers; + lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers); break; case 11: chip = "at86rf233"; @@ -1609,6 +1652,8 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->supported.channels[0] = 0x7FFF800; lp->hw->phy->current_channel = 13; lp->hw->phy->symbol_duration = 16; + lp->hw->phy->supported.tx_powers = at86rf233_powers; + lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf233_powers); break; default: chip = "unknown"; -- cgit v1.2.3 From 2d9fe7ab372a75c0148027bc48a18a64f150a7e7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:50 +0200 Subject: at86rf230: rework tx cca energy detection level This patch reworks the cca energy detection level handling. This contains a calculation which works on all transceiver types and add support for dump cca energy detection levels. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 79 ++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index dff7e47f5afb..833c42640e40 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -50,7 +50,6 @@ struct at86rf2xx_chip_data { int rssi_base_val; int (*set_channel)(struct at86rf230_local *, u8, u8); - int (*get_desense_steps)(struct at86rf230_local *, s32); int (*set_txpower)(struct at86rf230_local *, s32); }; @@ -1080,6 +1079,50 @@ at86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel) return at86rf230_write_subreg(lp, SR_CHANNEL, channel); } +#define AT86RF2XX_MAX_ED_LEVELS 0xF +static const s32 at86rf23x_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = { + -9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300, + -7100, -6900, -6700, -6500, -6300, -6100, +}; + +static const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = { + -10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, + -8000, -7800, -7600, -7400, -7200, +}; + +static const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = { + -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000, + -7800, -7600, -7400, -7200, -7000, +}; + +static inline int +at86rf212_update_cca_ed_level(struct at86rf230_local *lp, int rssi_base_val) +{ + unsigned int cca_ed_thres; + int rc; + + rc = at86rf230_read_subreg(lp, SR_CCA_ED_THRES, &cca_ed_thres); + if (rc < 0) + return rc; + + switch (rssi_base_val) { + case -98: + lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98; + lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98); + lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres]; + break; + case -100: + lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100; + lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100); + lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres]; + break; + default: + WARN_ON(1); + } + + return 0; +} + static int at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel) { @@ -1102,6 +1145,10 @@ at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel) if (rc < 0) return rc; + rc = at86rf212_update_cca_ed_level(lp, lp->data->rssi_base_val); + if (rc < 0) + return rc; + /* This sets the symbol_duration according frequency on the 212. * TODO move this handling while set channel and page in cfg802154. * We can do that, this timings are according 802.15.4 standard. @@ -1291,29 +1338,19 @@ at86rf230_set_cca_mode(struct ieee802154_hw *hw, return at86rf230_write_subreg(lp, SR_CCA_MODE, val); } -static int -at86rf212_get_desens_steps(struct at86rf230_local *lp, s32 level) -{ - return (level - lp->data->rssi_base_val) * 100 / 207; -} - -static int -at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level) -{ - return (level - lp->data->rssi_base_val) / 2; -} static int at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) { struct at86rf230_local *lp = hw->priv; - s32 level = mbm / 100; + u32 i; - if (level < lp->data->rssi_base_val || level > 30) - return -EINVAL; + for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) { + if (hw->phy->supported.cca_ed_levels[i] == mbm) + return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, i); + } - return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, - lp->data->get_desense_steps(lp, level)); + return -EINVAL; } static int @@ -1403,7 +1440,6 @@ static struct at86rf2xx_chip_data at86rf233_data = { .t_p_ack = 545, .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, - .get_desense_steps = at86rf23x_get_desens_steps, .set_txpower = at86rf23x_set_txpower, }; @@ -1417,7 +1453,6 @@ static struct at86rf2xx_chip_data at86rf231_data = { .t_p_ack = 545, .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, - .get_desense_steps = at86rf23x_get_desens_steps, .set_txpower = at86rf23x_set_txpower, }; @@ -1431,7 +1466,6 @@ static struct at86rf2xx_chip_data at86rf212_data = { .t_p_ack = 545, .rssi_base_val = -100, .set_channel = at86rf212_set_channel, - .get_desense_steps = at86rf212_get_desens_steps, .set_txpower = at86rf212_set_txpower, }; @@ -1618,6 +1652,9 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) | BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR); + lp->hw->phy->supported.cca_ed_levels = at86rf23x_ed_levels; + lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf23x_ed_levels); + lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; switch (part) { @@ -1645,6 +1682,8 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH; lp->hw->phy->supported.tx_powers = at86rf212_powers; lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers); + lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100; + lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100); break; case 11: chip = "at86rf233"; -- cgit v1.2.3 From cc643496c0c3f242e5df9dc2bc243764d269d4f1 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:51 +0200 Subject: at86rf230: add cca ed level reset value This patch adds reset values for cca ed level values after running reset procedure. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 833c42640e40..3aa7bc9488e4 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1661,7 +1661,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) case 2: chip = "at86rf230"; rc = -ENOTSUPP; - break; + goto not_supp; case 3: chip = "at86rf231"; lp->data = &at86rf231_data; @@ -1697,9 +1697,12 @@ at86rf230_detect_device(struct at86rf230_local *lp) default: chip = "unknown"; rc = -ENOTSUPP; - break; + goto not_supp; } + lp->hw->phy->cca_ed_level = lp->hw->phy->supported.cca_ed_levels[7]; + +not_supp: dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version); return rc; -- cgit v1.2.3 From 392f4e67ad96e1d686c700cba5e218d40347426d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:52 +0200 Subject: at86rf230: add reset states of tx power level This patch adds the reset states for tx power levels after running reset procedure. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 3aa7bc9488e4..5601c743fa7b 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1701,6 +1701,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) } lp->hw->phy->cca_ed_level = lp->hw->phy->supported.cca_ed_levels[7]; + lp->hw->phy->transmit_power = lp->hw->phy->supported.tx_powers[0]; not_supp: dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version); -- cgit v1.2.3 From cb97d9a3eb0be1e33db5535955e6629e800f3f0e Mon Sep 17 00:00:00 2001 From: Martin Townsend Date: Sun, 17 May 2015 21:44:54 +0200 Subject: mac802154: fakelb: Fix potential NULL pointer dereference. fakelb_hw_deliver creates a copy of the skb's header which can potentially return NULL so we now check for this before actually delivering to the 802.15.4 MAC layer. Signed-off-by: Martin Townsend Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 91bbf030a443..230f7da02165 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -69,7 +69,8 @@ fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb) spin_lock(&priv->lock); if (priv->working) { newskb = pskb_copy(skb, GFP_ATOMIC); - ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc); + if (newskb) + ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc); } spin_unlock(&priv->lock); } -- cgit v1.2.3 From a2c390aa3d67f0c3a1465e246d1b7468c37abae4 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:55 +0200 Subject: at86rf230: fix callback for aret handling This patch fix the complete callback for going into aret on. Currently we starting after a state change into aret on again a state change into aret on which is not necessary. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 5601c743fa7b..8d5ed6e23ddb 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1013,7 +1013,7 @@ at86rf230_xmit_start(void *context) if (lp->is_tx_from_off) { lp->is_tx_from_off = false; at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, - at86rf230_xmit_tx_on, + at86rf230_write_frame, false); } else { at86rf230_async_state_change(lp, ctx, STATE_TX_ON, -- cgit v1.2.3 From 7490b008d123f9bd781f51ad86b543aed49f6200 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:57 +0200 Subject: ieee802154: add support for atusb transceiver This patch adds support for the atusb transceiver. The current driver supports basic functionality only. Possible further tasks would be to sync functionality with the at86rf230 driver, because the atusb use internally an at86rf231 transceiver. Some of these features need a firmware update like AACK and ARET handling. I did small changes to this driver to work with xmit_async callback and setting of a random extended perm address. Signed-off-by: Alexander Aring Cc: Werner Almesberger Cc: Stefan Schmidt Cc: Richard Sharpe Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/Kconfig | 10 + drivers/net/ieee802154/Makefile | 1 + drivers/net/ieee802154/at86rf230.c | 199 +---------- drivers/net/ieee802154/at86rf230.h | 220 ++++++++++++ drivers/net/ieee802154/atusb.c | 692 +++++++++++++++++++++++++++++++++++++ drivers/net/ieee802154/atusb.h | 84 +++++ 6 files changed, 1009 insertions(+), 197 deletions(-) create mode 100644 drivers/net/ieee802154/at86rf230.h create mode 100644 drivers/net/ieee802154/atusb.c create mode 100644 drivers/net/ieee802154/atusb.h (limited to 'drivers') diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 1a3c3e57aa0b..1dd5ab8e5054 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -53,3 +53,13 @@ config IEEE802154_CC2520 This driver can also be built as a module. To do so, say M here. the module will be called 'cc2520'. + +config IEEE802154_ATUSB + tristate "ATUSB transceiver driver" + depends on IEEE802154_DRIVERS && MAC802154 && USB + ---help--- + Say Y here to enable the ATUSB IEEE 802.15.4 wireless + controller. + + This driver can also be built as a module. To do so say M here. + The module will be called 'atusb'. diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile index d77fa4d77e27..cf1d2a6db023 100644 --- a/drivers/net/ieee802154/Makefile +++ b/drivers/net/ieee802154/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o +obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 8d5ed6e23ddb..d417ceb67626 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -35,6 +35,8 @@ #include #include +#include "at86rf230.h" + struct at86rf230_local; /* at86rf2xx chip depend data. * All timings are in us. @@ -102,203 +104,6 @@ struct at86rf230_local { struct at86rf230_state_change tx; }; -#define RG_TRX_STATUS (0x01) -#define SR_TRX_STATUS 0x01, 0x1f, 0 -#define SR_RESERVED_01_3 0x01, 0x20, 5 -#define SR_CCA_STATUS 0x01, 0x40, 6 -#define SR_CCA_DONE 0x01, 0x80, 7 -#define RG_TRX_STATE (0x02) -#define SR_TRX_CMD 0x02, 0x1f, 0 -#define SR_TRAC_STATUS 0x02, 0xe0, 5 -#define RG_TRX_CTRL_0 (0x03) -#define SR_CLKM_CTRL 0x03, 0x07, 0 -#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 -#define SR_PAD_IO_CLKM 0x03, 0x30, 4 -#define SR_PAD_IO 0x03, 0xc0, 6 -#define RG_TRX_CTRL_1 (0x04) -#define SR_IRQ_POLARITY 0x04, 0x01, 0 -#define SR_IRQ_MASK_MODE 0x04, 0x02, 1 -#define SR_SPI_CMD_MODE 0x04, 0x0c, 2 -#define SR_RX_BL_CTRL 0x04, 0x10, 4 -#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5 -#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 -#define SR_PA_EXT_EN 0x04, 0x80, 7 -#define RG_PHY_TX_PWR (0x05) -#define SR_TX_PWR_23X 0x05, 0x0f, 0 -#define SR_PA_LT_230 0x05, 0x30, 4 -#define SR_PA_BUF_LT_230 0x05, 0xc0, 6 -#define SR_TX_PWR_212 0x05, 0x1f, 0 -#define SR_GC_PA_212 0x05, 0x60, 5 -#define SR_PA_BOOST_LT_212 0x05, 0x80, 7 -#define RG_PHY_RSSI (0x06) -#define SR_RSSI 0x06, 0x1f, 0 -#define SR_RND_VALUE 0x06, 0x60, 5 -#define SR_RX_CRC_VALID 0x06, 0x80, 7 -#define RG_PHY_ED_LEVEL (0x07) -#define SR_ED_LEVEL 0x07, 0xff, 0 -#define RG_PHY_CC_CCA (0x08) -#define SR_CHANNEL 0x08, 0x1f, 0 -#define SR_CCA_MODE 0x08, 0x60, 5 -#define SR_CCA_REQUEST 0x08, 0x80, 7 -#define RG_CCA_THRES (0x09) -#define SR_CCA_ED_THRES 0x09, 0x0f, 0 -#define SR_RESERVED_09_1 0x09, 0xf0, 4 -#define RG_RX_CTRL (0x0a) -#define SR_PDT_THRES 0x0a, 0x0f, 0 -#define SR_RESERVED_0a_1 0x0a, 0xf0, 4 -#define RG_SFD_VALUE (0x0b) -#define SR_SFD_VALUE 0x0b, 0xff, 0 -#define RG_TRX_CTRL_2 (0x0c) -#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 -#define SR_SUB_MODE 0x0c, 0x04, 2 -#define SR_BPSK_QPSK 0x0c, 0x08, 3 -#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 -#define SR_RESERVED_0c_5 0x0c, 0x60, 5 -#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 -#define RG_ANT_DIV (0x0d) -#define SR_ANT_CTRL 0x0d, 0x03, 0 -#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2 -#define SR_ANT_DIV_EN 0x0d, 0x08, 3 -#define SR_RESERVED_0d_2 0x0d, 0x70, 4 -#define SR_ANT_SEL 0x0d, 0x80, 7 -#define RG_IRQ_MASK (0x0e) -#define SR_IRQ_MASK 0x0e, 0xff, 0 -#define RG_IRQ_STATUS (0x0f) -#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 -#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 -#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 -#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 -#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4 -#define SR_IRQ_5_AMI 0x0f, 0x20, 5 -#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 -#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 -#define RG_VREG_CTRL (0x10) -#define SR_RESERVED_10_6 0x10, 0x03, 0 -#define SR_DVDD_OK 0x10, 0x04, 2 -#define SR_DVREG_EXT 0x10, 0x08, 3 -#define SR_RESERVED_10_3 0x10, 0x30, 4 -#define SR_AVDD_OK 0x10, 0x40, 6 -#define SR_AVREG_EXT 0x10, 0x80, 7 -#define RG_BATMON (0x11) -#define SR_BATMON_VTH 0x11, 0x0f, 0 -#define SR_BATMON_HR 0x11, 0x10, 4 -#define SR_BATMON_OK 0x11, 0x20, 5 -#define SR_RESERVED_11_1 0x11, 0xc0, 6 -#define RG_XOSC_CTRL (0x12) -#define SR_XTAL_TRIM 0x12, 0x0f, 0 -#define SR_XTAL_MODE 0x12, 0xf0, 4 -#define RG_RX_SYN (0x15) -#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0 -#define SR_RESERVED_15_2 0x15, 0x70, 4 -#define SR_RX_PDT_DIS 0x15, 0x80, 7 -#define RG_XAH_CTRL_1 (0x17) -#define SR_RESERVED_17_8 0x17, 0x01, 0 -#define SR_AACK_PROM_MODE 0x17, 0x02, 1 -#define SR_AACK_ACK_TIME 0x17, 0x04, 2 -#define SR_RESERVED_17_5 0x17, 0x08, 3 -#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 -#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 -#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 -#define SR_RESERVED_17_1 0x17, 0x80, 7 -#define RG_FTN_CTRL (0x18) -#define SR_RESERVED_18_2 0x18, 0x7f, 0 -#define SR_FTN_START 0x18, 0x80, 7 -#define RG_PLL_CF (0x1a) -#define SR_RESERVED_1a_2 0x1a, 0x7f, 0 -#define SR_PLL_CF_START 0x1a, 0x80, 7 -#define RG_PLL_DCU (0x1b) -#define SR_RESERVED_1b_3 0x1b, 0x3f, 0 -#define SR_RESERVED_1b_2 0x1b, 0x40, 6 -#define SR_PLL_DCU_START 0x1b, 0x80, 7 -#define RG_PART_NUM (0x1c) -#define SR_PART_NUM 0x1c, 0xff, 0 -#define RG_VERSION_NUM (0x1d) -#define SR_VERSION_NUM 0x1d, 0xff, 0 -#define RG_MAN_ID_0 (0x1e) -#define SR_MAN_ID_0 0x1e, 0xff, 0 -#define RG_MAN_ID_1 (0x1f) -#define SR_MAN_ID_1 0x1f, 0xff, 0 -#define RG_SHORT_ADDR_0 (0x20) -#define SR_SHORT_ADDR_0 0x20, 0xff, 0 -#define RG_SHORT_ADDR_1 (0x21) -#define SR_SHORT_ADDR_1 0x21, 0xff, 0 -#define RG_PAN_ID_0 (0x22) -#define SR_PAN_ID_0 0x22, 0xff, 0 -#define RG_PAN_ID_1 (0x23) -#define SR_PAN_ID_1 0x23, 0xff, 0 -#define RG_IEEE_ADDR_0 (0x24) -#define SR_IEEE_ADDR_0 0x24, 0xff, 0 -#define RG_IEEE_ADDR_1 (0x25) -#define SR_IEEE_ADDR_1 0x25, 0xff, 0 -#define RG_IEEE_ADDR_2 (0x26) -#define SR_IEEE_ADDR_2 0x26, 0xff, 0 -#define RG_IEEE_ADDR_3 (0x27) -#define SR_IEEE_ADDR_3 0x27, 0xff, 0 -#define RG_IEEE_ADDR_4 (0x28) -#define SR_IEEE_ADDR_4 0x28, 0xff, 0 -#define RG_IEEE_ADDR_5 (0x29) -#define SR_IEEE_ADDR_5 0x29, 0xff, 0 -#define RG_IEEE_ADDR_6 (0x2a) -#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 -#define RG_IEEE_ADDR_7 (0x2b) -#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 -#define RG_XAH_CTRL_0 (0x2c) -#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0 -#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 -#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 -#define RG_CSMA_SEED_0 (0x2d) -#define SR_CSMA_SEED_0 0x2d, 0xff, 0 -#define RG_CSMA_SEED_1 (0x2e) -#define SR_CSMA_SEED_1 0x2e, 0x07, 0 -#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3 -#define SR_AACK_DIS_ACK 0x2e, 0x10, 4 -#define SR_AACK_SET_PD 0x2e, 0x20, 5 -#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6 -#define RG_CSMA_BE (0x2f) -#define SR_MIN_BE 0x2f, 0x0f, 0 -#define SR_MAX_BE 0x2f, 0xf0, 4 - -#define CMD_REG 0x80 -#define CMD_REG_MASK 0x3f -#define CMD_WRITE 0x40 -#define CMD_FB 0x20 - -#define IRQ_BAT_LOW (1 << 7) -#define IRQ_TRX_UR (1 << 6) -#define IRQ_AMI (1 << 5) -#define IRQ_CCA_ED (1 << 4) -#define IRQ_TRX_END (1 << 3) -#define IRQ_RX_START (1 << 2) -#define IRQ_PLL_UNL (1 << 1) -#define IRQ_PLL_LOCK (1 << 0) - -#define IRQ_ACTIVE_HIGH 0 -#define IRQ_ACTIVE_LOW 1 - -#define STATE_P_ON 0x00 /* BUSY */ -#define STATE_BUSY_RX 0x01 -#define STATE_BUSY_TX 0x02 -#define STATE_FORCE_TRX_OFF 0x03 -#define STATE_FORCE_TX_ON 0x04 /* IDLE */ -/* 0x05 */ /* INVALID_PARAMETER */ -#define STATE_RX_ON 0x06 -/* 0x07 */ /* SUCCESS */ -#define STATE_TRX_OFF 0x08 -#define STATE_TX_ON 0x09 -/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */ -#define STATE_SLEEP 0x0F -#define STATE_PREP_DEEP_SLEEP 0x10 -#define STATE_BUSY_RX_AACK 0x11 -#define STATE_BUSY_TX_ARET 0x12 -#define STATE_RX_AACK_ON 0x16 -#define STATE_TX_ARET_ON 0x19 -#define STATE_RX_ON_NOCLK 0x1C -#define STATE_RX_AACK_ON_NOCLK 0x1D -#define STATE_BUSY_RX_AACK_NOCLK 0x1E -#define STATE_TRANSITION_IN_PROGRESS 0x1F - -#define TRX_STATE_MASK (0x1F) - #define AT86RF2XX_NUMREGS 0x3F static void diff --git a/drivers/net/ieee802154/at86rf230.h b/drivers/net/ieee802154/at86rf230.h new file mode 100644 index 000000000000..1e6d1cc677f6 --- /dev/null +++ b/drivers/net/ieee802154/at86rf230.h @@ -0,0 +1,220 @@ +/* + * AT86RF230/RF231 driver + * + * Copyright (C) 2009-2012 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + * + * Written by: + * Dmitry Eremin-Solenikov + * Alexander Smirnov + */ + +#ifndef _AT86RF230_H +#define _AT86RF230_H + +#define RG_TRX_STATUS (0x01) +#define SR_TRX_STATUS 0x01, 0x1f, 0 +#define SR_RESERVED_01_3 0x01, 0x20, 5 +#define SR_CCA_STATUS 0x01, 0x40, 6 +#define SR_CCA_DONE 0x01, 0x80, 7 +#define RG_TRX_STATE (0x02) +#define SR_TRX_CMD 0x02, 0x1f, 0 +#define SR_TRAC_STATUS 0x02, 0xe0, 5 +#define RG_TRX_CTRL_0 (0x03) +#define SR_CLKM_CTRL 0x03, 0x07, 0 +#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 +#define SR_PAD_IO_CLKM 0x03, 0x30, 4 +#define SR_PAD_IO 0x03, 0xc0, 6 +#define RG_TRX_CTRL_1 (0x04) +#define SR_IRQ_POLARITY 0x04, 0x01, 0 +#define SR_IRQ_MASK_MODE 0x04, 0x02, 1 +#define SR_SPI_CMD_MODE 0x04, 0x0c, 2 +#define SR_RX_BL_CTRL 0x04, 0x10, 4 +#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5 +#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 +#define SR_PA_EXT_EN 0x04, 0x80, 7 +#define RG_PHY_TX_PWR (0x05) +#define SR_TX_PWR_23X 0x05, 0x0f, 0 +#define SR_PA_LT_230 0x05, 0x30, 4 +#define SR_PA_BUF_LT_230 0x05, 0xc0, 6 +#define SR_TX_PWR_212 0x05, 0x1f, 0 +#define SR_GC_PA_212 0x05, 0x60, 5 +#define SR_PA_BOOST_LT_212 0x05, 0x80, 7 +#define RG_PHY_RSSI (0x06) +#define SR_RSSI 0x06, 0x1f, 0 +#define SR_RND_VALUE 0x06, 0x60, 5 +#define SR_RX_CRC_VALID 0x06, 0x80, 7 +#define RG_PHY_ED_LEVEL (0x07) +#define SR_ED_LEVEL 0x07, 0xff, 0 +#define RG_PHY_CC_CCA (0x08) +#define SR_CHANNEL 0x08, 0x1f, 0 +#define SR_CCA_MODE 0x08, 0x60, 5 +#define SR_CCA_REQUEST 0x08, 0x80, 7 +#define RG_CCA_THRES (0x09) +#define SR_CCA_ED_THRES 0x09, 0x0f, 0 +#define SR_RESERVED_09_1 0x09, 0xf0, 4 +#define RG_RX_CTRL (0x0a) +#define SR_PDT_THRES 0x0a, 0x0f, 0 +#define SR_RESERVED_0a_1 0x0a, 0xf0, 4 +#define RG_SFD_VALUE (0x0b) +#define SR_SFD_VALUE 0x0b, 0xff, 0 +#define RG_TRX_CTRL_2 (0x0c) +#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 +#define SR_SUB_MODE 0x0c, 0x04, 2 +#define SR_BPSK_QPSK 0x0c, 0x08, 3 +#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 +#define SR_RESERVED_0c_5 0x0c, 0x60, 5 +#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 +#define RG_ANT_DIV (0x0d) +#define SR_ANT_CTRL 0x0d, 0x03, 0 +#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2 +#define SR_ANT_DIV_EN 0x0d, 0x08, 3 +#define SR_RESERVED_0d_2 0x0d, 0x70, 4 +#define SR_ANT_SEL 0x0d, 0x80, 7 +#define RG_IRQ_MASK (0x0e) +#define SR_IRQ_MASK 0x0e, 0xff, 0 +#define RG_IRQ_STATUS (0x0f) +#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 +#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 +#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 +#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 +#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4 +#define SR_IRQ_5_AMI 0x0f, 0x20, 5 +#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 +#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 +#define RG_VREG_CTRL (0x10) +#define SR_RESERVED_10_6 0x10, 0x03, 0 +#define SR_DVDD_OK 0x10, 0x04, 2 +#define SR_DVREG_EXT 0x10, 0x08, 3 +#define SR_RESERVED_10_3 0x10, 0x30, 4 +#define SR_AVDD_OK 0x10, 0x40, 6 +#define SR_AVREG_EXT 0x10, 0x80, 7 +#define RG_BATMON (0x11) +#define SR_BATMON_VTH 0x11, 0x0f, 0 +#define SR_BATMON_HR 0x11, 0x10, 4 +#define SR_BATMON_OK 0x11, 0x20, 5 +#define SR_RESERVED_11_1 0x11, 0xc0, 6 +#define RG_XOSC_CTRL (0x12) +#define SR_XTAL_TRIM 0x12, 0x0f, 0 +#define SR_XTAL_MODE 0x12, 0xf0, 4 +#define RG_RX_SYN (0x15) +#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0 +#define SR_RESERVED_15_2 0x15, 0x70, 4 +#define SR_RX_PDT_DIS 0x15, 0x80, 7 +#define RG_XAH_CTRL_1 (0x17) +#define SR_RESERVED_17_8 0x17, 0x01, 0 +#define SR_AACK_PROM_MODE 0x17, 0x02, 1 +#define SR_AACK_ACK_TIME 0x17, 0x04, 2 +#define SR_RESERVED_17_5 0x17, 0x08, 3 +#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 +#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 +#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 +#define SR_RESERVED_17_1 0x17, 0x80, 7 +#define RG_FTN_CTRL (0x18) +#define SR_RESERVED_18_2 0x18, 0x7f, 0 +#define SR_FTN_START 0x18, 0x80, 7 +#define RG_PLL_CF (0x1a) +#define SR_RESERVED_1a_2 0x1a, 0x7f, 0 +#define SR_PLL_CF_START 0x1a, 0x80, 7 +#define RG_PLL_DCU (0x1b) +#define SR_RESERVED_1b_3 0x1b, 0x3f, 0 +#define SR_RESERVED_1b_2 0x1b, 0x40, 6 +#define SR_PLL_DCU_START 0x1b, 0x80, 7 +#define RG_PART_NUM (0x1c) +#define SR_PART_NUM 0x1c, 0xff, 0 +#define RG_VERSION_NUM (0x1d) +#define SR_VERSION_NUM 0x1d, 0xff, 0 +#define RG_MAN_ID_0 (0x1e) +#define SR_MAN_ID_0 0x1e, 0xff, 0 +#define RG_MAN_ID_1 (0x1f) +#define SR_MAN_ID_1 0x1f, 0xff, 0 +#define RG_SHORT_ADDR_0 (0x20) +#define SR_SHORT_ADDR_0 0x20, 0xff, 0 +#define RG_SHORT_ADDR_1 (0x21) +#define SR_SHORT_ADDR_1 0x21, 0xff, 0 +#define RG_PAN_ID_0 (0x22) +#define SR_PAN_ID_0 0x22, 0xff, 0 +#define RG_PAN_ID_1 (0x23) +#define SR_PAN_ID_1 0x23, 0xff, 0 +#define RG_IEEE_ADDR_0 (0x24) +#define SR_IEEE_ADDR_0 0x24, 0xff, 0 +#define RG_IEEE_ADDR_1 (0x25) +#define SR_IEEE_ADDR_1 0x25, 0xff, 0 +#define RG_IEEE_ADDR_2 (0x26) +#define SR_IEEE_ADDR_2 0x26, 0xff, 0 +#define RG_IEEE_ADDR_3 (0x27) +#define SR_IEEE_ADDR_3 0x27, 0xff, 0 +#define RG_IEEE_ADDR_4 (0x28) +#define SR_IEEE_ADDR_4 0x28, 0xff, 0 +#define RG_IEEE_ADDR_5 (0x29) +#define SR_IEEE_ADDR_5 0x29, 0xff, 0 +#define RG_IEEE_ADDR_6 (0x2a) +#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 +#define RG_IEEE_ADDR_7 (0x2b) +#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 +#define RG_XAH_CTRL_0 (0x2c) +#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0 +#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 +#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 +#define RG_CSMA_SEED_0 (0x2d) +#define SR_CSMA_SEED_0 0x2d, 0xff, 0 +#define RG_CSMA_SEED_1 (0x2e) +#define SR_CSMA_SEED_1 0x2e, 0x07, 0 +#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3 +#define SR_AACK_DIS_ACK 0x2e, 0x10, 4 +#define SR_AACK_SET_PD 0x2e, 0x20, 5 +#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6 +#define RG_CSMA_BE (0x2f) +#define SR_MIN_BE 0x2f, 0x0f, 0 +#define SR_MAX_BE 0x2f, 0xf0, 4 + +#define CMD_REG 0x80 +#define CMD_REG_MASK 0x3f +#define CMD_WRITE 0x40 +#define CMD_FB 0x20 + +#define IRQ_BAT_LOW BIT(7) +#define IRQ_TRX_UR BIT(6) +#define IRQ_AMI BIT(5) +#define IRQ_CCA_ED BIT(4) +#define IRQ_TRX_END BIT(3) +#define IRQ_RX_START BIT(2) +#define IRQ_PLL_UNL BIT(1) +#define IRQ_PLL_LOCK BIT(0) + +#define IRQ_ACTIVE_HIGH 0 +#define IRQ_ACTIVE_LOW 1 + +#define STATE_P_ON 0x00 /* BUSY */ +#define STATE_BUSY_RX 0x01 +#define STATE_BUSY_TX 0x02 +#define STATE_FORCE_TRX_OFF 0x03 +#define STATE_FORCE_TX_ON 0x04 /* IDLE */ +/* 0x05 */ /* INVALID_PARAMETER */ +#define STATE_RX_ON 0x06 +/* 0x07 */ /* SUCCESS */ +#define STATE_TRX_OFF 0x08 +#define STATE_TX_ON 0x09 +/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */ +#define STATE_SLEEP 0x0F +#define STATE_PREP_DEEP_SLEEP 0x10 +#define STATE_BUSY_RX_AACK 0x11 +#define STATE_BUSY_TX_ARET 0x12 +#define STATE_RX_AACK_ON 0x16 +#define STATE_TX_ARET_ON 0x19 +#define STATE_RX_ON_NOCLK 0x1C +#define STATE_RX_AACK_ON_NOCLK 0x1D +#define STATE_BUSY_RX_AACK_NOCLK 0x1E +#define STATE_TRANSITION_IN_PROGRESS 0x1F + +#define TRX_STATE_MASK (0x1F) + +#endif /* !_AT86RF230_H */ diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c new file mode 100644 index 000000000000..ea1259ef8508 --- /dev/null +++ b/drivers/net/ieee802154/atusb.c @@ -0,0 +1,692 @@ +/* + * atusb.c - Driver for the ATUSB IEEE 802.15.4 dongle + * + * Written 2013 by Werner Almesberger + * + * 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, version 2 + * + * Based on at86rf230.c and spi_atusb.c. + * at86rf230.c is + * Copyright (C) 2009 Siemens AG + * Written by: Dmitry Eremin-Solenikov + * + * spi_atusb.c is + * Copyright (c) 2011 Richard Sharpe + * Copyright (c) 2011 Stefan Schmidt + * Copyright (c) 2011 Werner Almesberger + * + * USB initialization is + * Copyright (c) 2013 Alexander Aring + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "at86rf230.h" +#include "atusb.h" + +#define ATUSB_JEDEC_ATMEL 0x1f /* JEDEC manufacturer ID */ + +#define ATUSB_NUM_RX_URBS 4 /* allow for a bit of local latency */ +#define ATUSB_ALLOC_DELAY_MS 100 /* delay after failed allocation */ +#define ATUSB_TX_TIMEOUT_MS 200 /* on the air timeout */ + +struct atusb { + struct ieee802154_hw *hw; + struct usb_device *usb_dev; + int shutdown; /* non-zero if shutting down */ + int err; /* set by first error */ + + /* RX variables */ + struct delayed_work work; /* memory allocations */ + struct usb_anchor idle_urbs; /* URBs waiting to be submitted */ + struct usb_anchor rx_urbs; /* URBs waiting for reception */ + + /* TX variables */ + struct usb_ctrlrequest tx_dr; + struct urb *tx_urb; + struct sk_buff *tx_skb; + uint8_t tx_ack_seq; /* current TX ACK sequence number */ +}; + +/* at86rf230.h defines values as tuples. We use the more + * traditional style of having registers and or-able values. SR_REG extracts + * the register number. SR_VALUE uses the shift to prepare a value accordingly. + */ + +#define __SR_REG(reg, mask, shift) (reg) +#define SR_REG(sr) __SR_REG(sr) + +#define __SR_VALUE(reg, mask, shift, val) ((val) << (shift)) +#define SR_VALUE(sr, val) __SR_VALUE(sr, (val)) + +/* ----- USB commands without data ----------------------------------------- */ + +/* To reduce the number of error checks in the code, we record the first error + * in atusb->err and reject all subsequent requests until the error is cleared. + */ + +static int atusb_control_msg(struct atusb *atusb, unsigned int pipe, + __u8 request, __u8 requesttype, + __u16 value, __u16 index, + void *data, __u16 size, int timeout) +{ + struct usb_device *usb_dev = atusb->usb_dev; + int ret; + + if (atusb->err) + return atusb->err; + + ret = usb_control_msg(usb_dev, pipe, request, requesttype, + value, index, data, size, timeout); + if (ret < 0) { + atusb->err = ret; + dev_err(&usb_dev->dev, + "atusb_control_msg: req 0x%02x val 0x%x idx 0x%x, error %d\n", + request, value, index, ret); + } + return ret; +} + +static int atusb_command(struct atusb *atusb, uint8_t cmd, uint8_t arg) +{ + struct usb_device *usb_dev = atusb->usb_dev; + + dev_dbg(&usb_dev->dev, "atusb_command: cmd = 0x%x\n", cmd); + return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0), + cmd, ATUSB_REQ_TO_DEV, arg, 0, NULL, 0, 1000); +} + +static int atusb_write_reg(struct atusb *atusb, uint8_t reg, uint8_t value) +{ + struct usb_device *usb_dev = atusb->usb_dev; + + dev_dbg(&usb_dev->dev, "atusb_write_reg: 0x%02x <- 0x%02x\n", + reg, value); + return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0), + ATUSB_REG_WRITE, ATUSB_REQ_TO_DEV, + value, reg, NULL, 0, 1000); +} + +static int atusb_read_reg(struct atusb *atusb, uint8_t reg) +{ + struct usb_device *usb_dev = atusb->usb_dev; + int ret; + uint8_t value; + + dev_dbg(&usb_dev->dev, "atusb: reg = 0x%x\n", reg); + ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), + ATUSB_REG_READ, ATUSB_REQ_FROM_DEV, + 0, reg, &value, 1, 1000); + return ret >= 0 ? value : ret; +} + +static int atusb_get_and_clear_error(struct atusb *atusb) +{ + int err = atusb->err; + + atusb->err = 0; + return err; +} + +/* ----- skb allocation ---------------------------------------------------- */ + +#define MAX_PSDU 127 +#define MAX_RX_XFER (1 + MAX_PSDU + 2 + 1) /* PHR+PSDU+CRC+LQI */ + +#define SKB_ATUSB(skb) (*(struct atusb **)(skb)->cb) + +static void atusb_in(struct urb *urb); + +static int atusb_submit_rx_urb(struct atusb *atusb, struct urb *urb) +{ + struct usb_device *usb_dev = atusb->usb_dev; + struct sk_buff *skb = urb->context; + int ret; + + if (!skb) { + skb = alloc_skb(MAX_RX_XFER, GFP_KERNEL); + if (!skb) { + dev_warn_ratelimited(&usb_dev->dev, + "atusb_in: can't allocate skb\n"); + return -ENOMEM; + } + skb_put(skb, MAX_RX_XFER); + SKB_ATUSB(skb) = atusb; + } + + usb_fill_bulk_urb(urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1), + skb->data, MAX_RX_XFER, atusb_in, skb); + usb_anchor_urb(urb, &atusb->rx_urbs); + + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + kfree_skb(skb); + urb->context = NULL; + } + return ret; +} + +static void atusb_work_urbs(struct work_struct *work) +{ + struct atusb *atusb = + container_of(to_delayed_work(work), struct atusb, work); + struct usb_device *usb_dev = atusb->usb_dev; + struct urb *urb; + int ret; + + if (atusb->shutdown) + return; + + do { + urb = usb_get_from_anchor(&atusb->idle_urbs); + if (!urb) + return; + ret = atusb_submit_rx_urb(atusb, urb); + } while (!ret); + + usb_anchor_urb(urb, &atusb->idle_urbs); + dev_warn_ratelimited(&usb_dev->dev, + "atusb_in: can't allocate/submit URB (%d)\n", ret); + schedule_delayed_work(&atusb->work, + msecs_to_jiffies(ATUSB_ALLOC_DELAY_MS) + 1); +} + +/* ----- Asynchronous USB -------------------------------------------------- */ + +static void atusb_tx_done(struct atusb *atusb, uint8_t seq) +{ + struct usb_device *usb_dev = atusb->usb_dev; + uint8_t expect = atusb->tx_ack_seq; + + dev_dbg(&usb_dev->dev, "atusb_tx_done (0x%02x/0x%02x)\n", seq, expect); + if (seq == expect) { + /* TODO check for ifs handling in firmware */ + ieee802154_xmit_complete(atusb->hw, atusb->tx_skb, false); + } else { + /* TODO I experience this case when atusb has a tx complete + * irq before probing, we should fix the firmware it's an + * unlikely case now that seq == expect is then true, but can + * happen and fail with a tx_skb = NULL; + */ + ieee802154_wake_queue(atusb->hw); + if (atusb->tx_skb) + dev_kfree_skb_irq(atusb->tx_skb); + } +} + +static void atusb_in_good(struct urb *urb) +{ + struct usb_device *usb_dev = urb->dev; + struct sk_buff *skb = urb->context; + struct atusb *atusb = SKB_ATUSB(skb); + uint8_t len, lqi; + + if (!urb->actual_length) { + dev_dbg(&usb_dev->dev, "atusb_in: zero-sized URB ?\n"); + return; + } + + len = *skb->data; + + if (urb->actual_length == 1) { + atusb_tx_done(atusb, len); + return; + } + + if (len + 1 > urb->actual_length - 1) { + dev_dbg(&usb_dev->dev, "atusb_in: frame len %d+1 > URB %u-1\n", + len, urb->actual_length); + return; + } + + if (!ieee802154_is_valid_psdu_len(len)) { + dev_dbg(&usb_dev->dev, "atusb_in: frame corrupted\n"); + return; + } + + lqi = skb->data[len + 1]; + dev_dbg(&usb_dev->dev, "atusb_in: rx len %d lqi 0x%02x\n", len, lqi); + skb_pull(skb, 1); /* remove PHR */ + skb_trim(skb, len); /* get payload only */ + ieee802154_rx_irqsafe(atusb->hw, skb, lqi); + urb->context = NULL; /* skb is gone */ +} + +static void atusb_in(struct urb *urb) +{ + struct usb_device *usb_dev = urb->dev; + struct sk_buff *skb = urb->context; + struct atusb *atusb = SKB_ATUSB(skb); + + dev_dbg(&usb_dev->dev, "atusb_in: status %d len %d\n", + urb->status, urb->actual_length); + if (urb->status) { + if (urb->status == -ENOENT) { /* being killed */ + kfree_skb(skb); + urb->context = NULL; + return; + } + dev_dbg(&usb_dev->dev, "atusb_in: URB error %d\n", urb->status); + } else { + atusb_in_good(urb); + } + + usb_anchor_urb(urb, &atusb->idle_urbs); + if (!atusb->shutdown) + schedule_delayed_work(&atusb->work, 0); +} + +/* ----- URB allocation/deallocation --------------------------------------- */ + +static void atusb_free_urbs(struct atusb *atusb) +{ + struct urb *urb; + + while (1) { + urb = usb_get_from_anchor(&atusb->idle_urbs); + if (!urb) + break; + if (urb->context) + kfree_skb(urb->context); + usb_free_urb(urb); + } +} + +static int atusb_alloc_urbs(struct atusb *atusb, int n) +{ + struct urb *urb; + + while (n) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + atusb_free_urbs(atusb); + return -ENOMEM; + } + usb_anchor_urb(urb, &atusb->idle_urbs); + n--; + } + return 0; +} + +/* ----- IEEE 802.15.4 interface operations -------------------------------- */ + +static void atusb_xmit_complete(struct urb *urb) +{ + dev_dbg(&urb->dev->dev, "atusb_xmit urb completed"); +} + +static int atusb_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +{ + struct atusb *atusb = hw->priv; + struct usb_device *usb_dev = atusb->usb_dev; + int ret; + + dev_dbg(&usb_dev->dev, "atusb_xmit (%d)\n", skb->len); + atusb->tx_skb = skb; + atusb->tx_ack_seq++; + atusb->tx_dr.wIndex = cpu_to_le16(atusb->tx_ack_seq); + atusb->tx_dr.wLength = cpu_to_le16(skb->len); + + usb_fill_control_urb(atusb->tx_urb, usb_dev, + usb_sndctrlpipe(usb_dev, 0), + (unsigned char *)&atusb->tx_dr, skb->data, + skb->len, atusb_xmit_complete, NULL); + ret = usb_submit_urb(atusb->tx_urb, GFP_ATOMIC); + dev_dbg(&usb_dev->dev, "atusb_xmit done (%d)\n", ret); + return ret; +} + +static int atusb_channel(struct ieee802154_hw *hw, u8 page, u8 channel) +{ + struct atusb *atusb = hw->priv; + int ret; + + /* This implicitly sets the CCA (Clear Channel Assessment) mode to 0, + * "Mode 3a, Carrier sense OR energy above threshold". + * We should probably make this configurable. @@@ + */ + ret = atusb_write_reg(atusb, RG_PHY_CC_CCA, channel); + if (ret < 0) + return ret; + msleep(1); /* @@@ ugly synchronization */ + return 0; +} + +static int atusb_ed(struct ieee802154_hw *hw, u8 *level) +{ + /* @@@ not used by the stack yet */ + *level = 0; + return 0; +} + +static int atusb_set_hw_addr_filt(struct ieee802154_hw *hw, + struct ieee802154_hw_addr_filt *filt, + unsigned long changed) +{ + struct atusb *atusb = hw->priv; + struct device *dev = &atusb->usb_dev->dev; + uint8_t reg; + + if (changed & IEEE802154_AFILT_SADDR_CHANGED) { + u16 addr = le16_to_cpu(filt->short_addr); + + dev_vdbg(dev, "atusb_set_hw_addr_filt called for saddr\n"); + atusb_write_reg(atusb, RG_SHORT_ADDR_0, addr); + atusb_write_reg(atusb, RG_SHORT_ADDR_1, addr >> 8); + } + + if (changed & IEEE802154_AFILT_PANID_CHANGED) { + u16 pan = le16_to_cpu(filt->pan_id); + + dev_vdbg(dev, "atusb_set_hw_addr_filt called for pan id\n"); + atusb_write_reg(atusb, RG_PAN_ID_0, pan); + atusb_write_reg(atusb, RG_PAN_ID_1, pan >> 8); + } + + if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { + u8 i, addr[IEEE802154_EXTENDED_ADDR_LEN]; + + memcpy(addr, &filt->ieee_addr, IEEE802154_EXTENDED_ADDR_LEN); + dev_vdbg(dev, "atusb_set_hw_addr_filt called for IEEE addr\n"); + for (i = 0; i < 8; i++) + atusb_write_reg(atusb, RG_IEEE_ADDR_0 + i, addr[i]); + } + + if (changed & IEEE802154_AFILT_PANC_CHANGED) { + dev_vdbg(dev, + "atusb_set_hw_addr_filt called for panc change\n"); + reg = atusb_read_reg(atusb, SR_REG(SR_AACK_I_AM_COORD)); + if (filt->pan_coord) + reg |= SR_VALUE(SR_AACK_I_AM_COORD, 1); + else + reg &= ~SR_VALUE(SR_AACK_I_AM_COORD, 1); + atusb_write_reg(atusb, SR_REG(SR_AACK_I_AM_COORD), reg); + } + + return atusb_get_and_clear_error(atusb); +} + +static int atusb_start(struct ieee802154_hw *hw) +{ + struct atusb *atusb = hw->priv; + struct usb_device *usb_dev = atusb->usb_dev; + int ret; + + dev_dbg(&usb_dev->dev, "atusb_start\n"); + schedule_delayed_work(&atusb->work, 0); + atusb_command(atusb, ATUSB_RX_MODE, 1); + ret = atusb_get_and_clear_error(atusb); + if (ret < 0) + usb_kill_anchored_urbs(&atusb->idle_urbs); + return ret; +} + +static void atusb_stop(struct ieee802154_hw *hw) +{ + struct atusb *atusb = hw->priv; + struct usb_device *usb_dev = atusb->usb_dev; + + dev_dbg(&usb_dev->dev, "atusb_stop\n"); + usb_kill_anchored_urbs(&atusb->idle_urbs); + atusb_command(atusb, ATUSB_RX_MODE, 0); + atusb_get_and_clear_error(atusb); +} + +static struct ieee802154_ops atusb_ops = { + .owner = THIS_MODULE, + .xmit_async = atusb_xmit, + .ed = atusb_ed, + .set_channel = atusb_channel, + .start = atusb_start, + .stop = atusb_stop, + .set_hw_addr_filt = atusb_set_hw_addr_filt, +}; + +/* ----- Firmware and chip version information ----------------------------- */ + +static int atusb_get_and_show_revision(struct atusb *atusb) +{ + struct usb_device *usb_dev = atusb->usb_dev; + unsigned char buffer[3]; + int ret; + + /* Get a couple of the ATMega Firmware values */ + ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), + ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0, + buffer, 3, 1000); + if (ret >= 0) + dev_info(&usb_dev->dev, + "Firmware: major: %u, minor: %u, hardware type: %u\n", + buffer[0], buffer[1], buffer[2]); + + return ret; +} + +static int atusb_get_and_show_build(struct atusb *atusb) +{ + struct usb_device *usb_dev = atusb->usb_dev; + char build[ATUSB_BUILD_SIZE + 1]; + int ret; + + ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), + ATUSB_BUILD, ATUSB_REQ_FROM_DEV, 0, 0, + build, ATUSB_BUILD_SIZE, 1000); + if (ret >= 0) { + build[ret] = 0; + dev_info(&usb_dev->dev, "Firmware: build %s\n", build); + } + + return ret; +} + +static int atusb_get_and_show_chip(struct atusb *atusb) +{ + struct usb_device *usb_dev = atusb->usb_dev; + uint8_t man_id_0, man_id_1, part_num, version_num; + + man_id_0 = atusb_read_reg(atusb, RG_MAN_ID_0); + man_id_1 = atusb_read_reg(atusb, RG_MAN_ID_1); + part_num = atusb_read_reg(atusb, RG_PART_NUM); + version_num = atusb_read_reg(atusb, RG_VERSION_NUM); + + if (atusb->err) + return atusb->err; + + if ((man_id_1 << 8 | man_id_0) != ATUSB_JEDEC_ATMEL) { + dev_err(&usb_dev->dev, + "non-Atmel transceiver xxxx%02x%02x\n", + man_id_1, man_id_0); + goto fail; + } + if (part_num != 3) { + dev_err(&usb_dev->dev, + "unexpected transceiver, part 0x%02x version 0x%02x\n", + part_num, version_num); + goto fail; + } + + dev_info(&usb_dev->dev, "ATUSB: AT86RF231 version %d\n", version_num); + + return 0; + +fail: + atusb->err = -ENODEV; + return -ENODEV; +} + +/* ----- Setup ------------------------------------------------------------- */ + +static int atusb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *usb_dev = interface_to_usbdev(interface); + struct ieee802154_hw *hw; + struct atusb *atusb = NULL; + int ret = -ENOMEM; + + hw = ieee802154_alloc_hw(sizeof(struct atusb), &atusb_ops); + if (!hw) + return -ENOMEM; + + atusb = hw->priv; + atusb->hw = hw; + atusb->usb_dev = usb_get_dev(usb_dev); + usb_set_intfdata(interface, atusb); + + atusb->shutdown = 0; + atusb->err = 0; + INIT_DELAYED_WORK(&atusb->work, atusb_work_urbs); + init_usb_anchor(&atusb->idle_urbs); + init_usb_anchor(&atusb->rx_urbs); + + if (atusb_alloc_urbs(atusb, ATUSB_NUM_RX_URBS)) + goto fail; + + atusb->tx_dr.bRequestType = ATUSB_REQ_TO_DEV; + atusb->tx_dr.bRequest = ATUSB_TX; + atusb->tx_dr.wValue = cpu_to_le16(0); + + atusb->tx_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!atusb->tx_urb) + goto fail; + + hw->parent = &usb_dev->dev; + hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT; + + hw->phy->current_page = 0; + hw->phy->current_channel = 11; /* reset default */ + hw->phy->supported.channels[0] = 0x7FFF800; + ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); + + atusb_command(atusb, ATUSB_RF_RESET, 0); + atusb_get_and_show_chip(atusb); + atusb_get_and_show_revision(atusb); + atusb_get_and_show_build(atusb); + ret = atusb_get_and_clear_error(atusb); + if (ret) { + dev_err(&atusb->usb_dev->dev, + "%s: initialization failed, error = %d\n", + __func__, ret); + goto fail; + } + + ret = ieee802154_register_hw(hw); + if (ret) + goto fail; + + /* If we just powered on, we're now in P_ON and need to enter TRX_OFF + * explicitly. Any resets after that will send us straight to TRX_OFF, + * making the command below redundant. + */ + atusb_write_reg(atusb, RG_TRX_STATE, STATE_FORCE_TRX_OFF); + msleep(1); /* reset => TRX_OFF, tTR13 = 37 us */ + +#if 0 + /* Calculating the maximum time available to empty the frame buffer + * on reception: + * + * According to [1], the inter-frame gap is + * R * 20 * 16 us + 128 us + * where R is a random number from 0 to 7. Furthermore, we have 20 bit + * times (80 us at 250 kbps) of SHR of the next frame before the + * transceiver begins storing data in the frame buffer. + * + * This yields a minimum time of 208 us between the last data of a + * frame and the first data of the next frame. This time is further + * reduced by interrupt latency in the atusb firmware. + * + * atusb currently needs about 500 us to retrieve a maximum-sized + * frame. We therefore have to allow reception of a new frame to begin + * while we retrieve the previous frame. + * + * [1] "JN-AN-1035 Calculating data rates in an IEEE 802.15.4-based + * network", Jennic 2006. + * http://www.jennic.com/download_file.php?supportFile=JN-AN-1035%20Calculating%20802-15-4%20Data%20Rates-1v0.pdf + */ + + atusb_write_reg(atusb, + SR_REG(SR_RX_SAFE_MODE), SR_VALUE(SR_RX_SAFE_MODE, 1)); +#endif + atusb_write_reg(atusb, RG_IRQ_MASK, 0xff); + + ret = atusb_get_and_clear_error(atusb); + if (!ret) + return 0; + + dev_err(&atusb->usb_dev->dev, + "%s: setup failed, error = %d\n", + __func__, ret); + + ieee802154_unregister_hw(hw); +fail: + atusb_free_urbs(atusb); + usb_kill_urb(atusb->tx_urb); + usb_free_urb(atusb->tx_urb); + usb_put_dev(usb_dev); + ieee802154_free_hw(hw); + return ret; +} + +static void atusb_disconnect(struct usb_interface *interface) +{ + struct atusb *atusb = usb_get_intfdata(interface); + + dev_dbg(&atusb->usb_dev->dev, "atusb_disconnect\n"); + + atusb->shutdown = 1; + cancel_delayed_work_sync(&atusb->work); + + usb_kill_anchored_urbs(&atusb->rx_urbs); + atusb_free_urbs(atusb); + usb_kill_urb(atusb->tx_urb); + usb_free_urb(atusb->tx_urb); + + ieee802154_unregister_hw(atusb->hw); + + ieee802154_free_hw(atusb->hw); + + usb_set_intfdata(interface, NULL); + usb_put_dev(atusb->usb_dev); + + pr_debug("atusb_disconnect done\n"); +} + +/* The devices we work with */ +static const struct usb_device_id atusb_device_table[] = { + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ATUSB_VENDOR_ID, + .idProduct = ATUSB_PRODUCT_ID, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC + }, + /* end with null element */ + {} +}; +MODULE_DEVICE_TABLE(usb, atusb_device_table); + +static struct usb_driver atusb_driver = { + .name = "atusb", + .probe = atusb_probe, + .disconnect = atusb_disconnect, + .id_table = atusb_device_table, +}; +module_usb_driver(atusb_driver); + +MODULE_AUTHOR("Alexander Aring "); +MODULE_AUTHOR("Richard Sharpe "); +MODULE_AUTHOR("Stefan Schmidt "); +MODULE_AUTHOR("Werner Almesberger "); +MODULE_DESCRIPTION("ATUSB IEEE 802.15.4 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ieee802154/atusb.h b/drivers/net/ieee802154/atusb.h new file mode 100644 index 000000000000..0690edcad57b --- /dev/null +++ b/drivers/net/ieee802154/atusb.h @@ -0,0 +1,84 @@ +/* + * atusb.h - Definitions shared between kernel and ATUSB firmware + * + * Written 2013 by Werner Almesberger + * + * 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, version 2, or + * (at your option) any later version. + * + * This file should be identical for kernel and firmware. + * Kernel: drivers/net/ieee802154/atusb.h + * Firmware: ben-wpan/atusb/fw/include/atusb/atusb.h + */ + +#ifndef _ATUSB_H +#define _ATUSB_H + +#define ATUSB_VENDOR_ID 0x20b7 /* Qi Hardware*/ +#define ATUSB_PRODUCT_ID 0x1540 /* 802.15.4, device 0 */ + /* -- - - */ + +#define ATUSB_BUILD_SIZE 256 /* maximum build version/date message length */ + +/* Commands to our device. Make sure this is synced with the firmware */ +enum atusb_requests { + ATUSB_ID = 0x00, /* system status/control grp */ + ATUSB_BUILD, + ATUSB_RESET, + ATUSB_RF_RESET = 0x10, /* debug/test group */ + ATUSB_POLL_INT, + ATUSB_TEST, /* atusb-sil only */ + ATUSB_TIMER, + ATUSB_GPIO, + ATUSB_SLP_TR, + ATUSB_GPIO_CLEANUP, + ATUSB_REG_WRITE = 0x20, /* transceiver group */ + ATUSB_REG_READ, + ATUSB_BUF_WRITE, + ATUSB_BUF_READ, + ATUSB_SRAM_WRITE, + ATUSB_SRAM_READ, + ATUSB_SPI_WRITE = 0x30, /* SPI group */ + ATUSB_SPI_READ1, + ATUSB_SPI_READ2, + ATUSB_SPI_WRITE2_SYNC, + ATUSB_RX_MODE = 0x40, /* HardMAC group */ + ATUSB_TX, +}; + +/* Direction bRequest wValue wIndex wLength + * + * ->host ATUSB_ID - - 3 + * ->host ATUSB_BUILD - - #bytes + * host-> ATUSB_RESET - - 0 + * + * host-> ATUSB_RF_RESET - - 0 + * ->host ATUSB_POLL_INT - - 1 + * host-> ATUSB_TEST - - 0 + * ->host ATUSB_TIMER - - #bytes (6) + * ->host ATUSB_GPIO dir+data mask+p# 3 + * host-> ATUSB_SLP_TR - - 0 + * host-> ATUSB_GPIO_CLEANUP - - 0 + * + * host-> ATUSB_REG_WRITE value addr 0 + * ->host ATUSB_REG_READ - addr 1 + * host-> ATUSB_BUF_WRITE - - #bytes + * ->host ATUSB_BUF_READ - - #bytes + * host-> ATUSB_SRAM_WRITE - addr #bytes + * ->host ATUSB_SRAM_READ - addr #bytes + * + * host-> ATUSB_SPI_WRITE byte0 byte1 #bytes + * ->host ATUSB_SPI_READ1 byte0 - #bytes + * ->host ATUSB_SPI_READ2 byte0 byte1 #bytes + * ->host ATUSB_SPI_WRITE2_SYNC byte0 byte1 0/1 + * + * host-> ATUSB_RX_MODE on - 0 + * host-> ATUSB_TX flags ack_seq #bytes + */ + +#define ATUSB_REQ_FROM_DEV (USB_TYPE_VENDOR | USB_DIR_IN) +#define ATUSB_REQ_TO_DEV (USB_TYPE_VENDOR | USB_DIR_OUT) + +#endif /* !_ATUSB_H */ -- cgit v1.2.3 From 7e57905ba6c825f38f146b5f8974c2ce27f299bb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:58 +0200 Subject: fakelb: creating two virtual phys per default This patch change the default virtual wpan phys of fakelb driver from one to two. To have one virtual phy makes no sense, because it need at least two virtual phy's to speak to each other. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 230f7da02165..cc1c7df25009 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -27,7 +27,7 @@ #include #include -static int numlbs = 1; +static int numlbs = 2; struct fakelb_dev_priv { struct ieee802154_hw *hw; -- cgit v1.2.3 From 3186d3d7aec3b2f242abbc0a0219226e7705c905 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:59 +0200 Subject: fakelb: use list_for_each_entry_safe Iterate and removing items from a list, we should use list_for_each_entry_safe instead list_for_each_entry to avoid accidents by removing. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index cc1c7df25009..66f99c4f9768 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -215,7 +215,7 @@ static void fakelb_del(struct fakelb_dev_priv *priv) static int fakelb_probe(struct platform_device *pdev) { struct fakelb_priv *priv; - struct fakelb_dev_priv *dp; + struct fakelb_dev_priv *dp, *tmp; int err = -ENOMEM; int i; @@ -238,7 +238,7 @@ static int fakelb_probe(struct platform_device *pdev) return 0; err_slave: - list_for_each_entry(dp, &priv->list, list) + list_for_each_entry_safe(dp, tmp, &priv->list, list) fakelb_del(dp); err_alloc: return err; -- cgit v1.2.3 From db3f5d0df9af1e5965e64595595a6a719c42fcf3 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:00 +0200 Subject: fakelb: rename fakelb_dev_priv to fakelb_phy This patch renames fakelb_dev_priv to fakelb_phy. We don't faking devices here, we fake wpan phys. This avoids also confusing with the variable priv, which is used several times in this driver to represent this structure. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 93 +++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 66f99c4f9768..5c4fbb861eb0 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -29,7 +29,7 @@ static int numlbs = 2; -struct fakelb_dev_priv { +struct fakelb_phy { struct ieee802154_hw *hw; struct list_head list; @@ -62,36 +62,37 @@ fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) } static void -fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb) +fakelb_hw_deliver(struct fakelb_phy *phy, struct sk_buff *skb) { struct sk_buff *newskb; - spin_lock(&priv->lock); - if (priv->working) { + spin_lock(&phy->lock); + if (phy->working) { newskb = pskb_copy(skb, GFP_ATOMIC); if (newskb) - ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc); + ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); } - spin_unlock(&priv->lock); + spin_unlock(&phy->lock); } static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) { - struct fakelb_dev_priv *priv = hw->priv; - struct fakelb_priv *fake = priv->fake; + struct fakelb_phy *current_phy = hw->priv; + struct fakelb_priv *fake = current_phy->fake; read_lock_bh(&fake->lock); - if (priv->list.next == priv->list.prev) { + if (current_phy->list.next == current_phy->list.prev) { /* we are the only one device */ - fakelb_hw_deliver(priv, skb); + fakelb_hw_deliver(current_phy, skb); } else { - struct fakelb_dev_priv *dp; - list_for_each_entry(dp, &priv->fake->list, list) { - if (dp != priv && - (dp->hw->phy->current_channel == - priv->hw->phy->current_channel)) - fakelb_hw_deliver(dp, skb); + struct fakelb_phy *phy; + + list_for_each_entry(phy, ¤t_phy->fake->list, list) { + if (current_phy != phy && + (phy->hw->phy->current_channel == + current_phy->hw->phy->current_channel)) + fakelb_hw_deliver(phy, skb); } } read_unlock_bh(&fake->lock); @@ -101,26 +102,26 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) static int fakelb_hw_start(struct ieee802154_hw *hw) { - struct fakelb_dev_priv *priv = hw->priv; + struct fakelb_phy *phy = hw->priv; int ret = 0; - spin_lock(&priv->lock); - if (priv->working) + spin_lock(&phy->lock); + if (phy->working) ret = -EBUSY; else - priv->working = 1; - spin_unlock(&priv->lock); + phy->working = 1; + spin_unlock(&phy->lock); return ret; } static void fakelb_hw_stop(struct ieee802154_hw *hw) { - struct fakelb_dev_priv *priv = hw->priv; + struct fakelb_phy *phy = hw->priv; - spin_lock(&priv->lock); - priv->working = 0; - spin_unlock(&priv->lock); + spin_lock(&phy->lock); + phy->working = 0; + spin_unlock(&phy->lock); } static const struct ieee802154_ops fakelb_ops = { @@ -138,16 +139,16 @@ MODULE_PARM_DESC(numlbs, " number of pseudo devices"); static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) { - struct fakelb_dev_priv *priv; + struct fakelb_phy *phy; int err; struct ieee802154_hw *hw; - hw = ieee802154_alloc_hw(sizeof(*priv), &fakelb_ops); + hw = ieee802154_alloc_hw(sizeof(*phy), &fakelb_ops); if (!hw) return -ENOMEM; - priv = hw->priv; - priv->hw = hw; + phy = hw->priv; + phy->hw = hw; /* 868 MHz BPSK 802.15.4-2003 */ hw->phy->supported.channels[0] |= 1; @@ -180,10 +181,10 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) /* 950 MHz GFSK 802.15.4d-2009 */ hw->phy->supported.channels[6] |= 0x3ffc00; - INIT_LIST_HEAD(&priv->list); - priv->fake = fake; + INIT_LIST_HEAD(&phy->list); + phy->fake = fake; - spin_lock_init(&priv->lock); + spin_lock_init(&phy->lock); hw->parent = dev; @@ -192,30 +193,30 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) goto err_reg; write_lock_bh(&fake->lock); - list_add_tail(&priv->list, &fake->list); + list_add_tail(&phy->list, &fake->list); write_unlock_bh(&fake->lock); return 0; err_reg: - ieee802154_free_hw(priv->hw); + ieee802154_free_hw(phy->hw); return err; } -static void fakelb_del(struct fakelb_dev_priv *priv) +static void fakelb_del(struct fakelb_phy *phy) { - write_lock_bh(&priv->fake->lock); - list_del(&priv->list); - write_unlock_bh(&priv->fake->lock); + write_lock_bh(&phy->fake->lock); + list_del(&phy->list); + write_unlock_bh(&phy->fake->lock); - ieee802154_unregister_hw(priv->hw); - ieee802154_free_hw(priv->hw); + ieee802154_unregister_hw(phy->hw); + ieee802154_free_hw(phy->hw); } static int fakelb_probe(struct platform_device *pdev) { struct fakelb_priv *priv; - struct fakelb_dev_priv *dp, *tmp; + struct fakelb_phy *phy, *tmp; int err = -ENOMEM; int i; @@ -238,8 +239,8 @@ static int fakelb_probe(struct platform_device *pdev) return 0; err_slave: - list_for_each_entry_safe(dp, tmp, &priv->list, list) - fakelb_del(dp); + list_for_each_entry_safe(phy, tmp, &priv->list, list) + fakelb_del(phy); err_alloc: return err; } @@ -247,10 +248,10 @@ err_alloc: static int fakelb_remove(struct platform_device *pdev) { struct fakelb_priv *priv = platform_get_drvdata(pdev); - struct fakelb_dev_priv *dp, *temp; + struct fakelb_phy *phy, *temp; - list_for_each_entry_safe(dp, temp, &priv->list, list) - fakelb_del(dp); + list_for_each_entry_safe(phy, temp, &priv->list, list) + fakelb_del(phy); return 0; } -- cgit v1.2.3 From 9f8b97f888445b737ea3716ca53498663e18d971 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:01 +0200 Subject: fakelb: don't deliver when one phy A real phy don't transmit the transmitted frame back to the phy. This behaviour will confuse the 6LoWPAN and the upper IPv6 neighbour discovery cache. We need now at least two virtual phy's to creating a virtual wpan network. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 5c4fbb861eb0..d5fb77678349 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -80,20 +80,16 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) { struct fakelb_phy *current_phy = hw->priv; struct fakelb_priv *fake = current_phy->fake; + struct fakelb_phy *phy; read_lock_bh(&fake->lock); - if (current_phy->list.next == current_phy->list.prev) { - /* we are the only one device */ - fakelb_hw_deliver(current_phy, skb); - } else { - struct fakelb_phy *phy; - - list_for_each_entry(phy, ¤t_phy->fake->list, list) { - if (current_phy != phy && - (phy->hw->phy->current_channel == - current_phy->hw->phy->current_channel)) - fakelb_hw_deliver(phy, skb); - } + list_for_each_entry(phy, ¤t_phy->fake->list, list) { + if (current_phy == phy) + continue; + + if (phy->hw->phy->current_channel == + current_phy->hw->phy->current_channel) + fakelb_hw_deliver(phy, skb); } read_unlock_bh(&fake->lock); -- cgit v1.2.3 From 3335d98c69b1b09b963d09c8475c40bd8988c994 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:02 +0200 Subject: fakelb: declare rwlock static This patch moves the rwlock declarition into a static variable. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index d5fb77678349..43370fb48cf6 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -28,6 +28,7 @@ #include static int numlbs = 2; +static DEFINE_RWLOCK(fakelb_lock); struct fakelb_phy { struct ieee802154_hw *hw; @@ -41,7 +42,6 @@ struct fakelb_phy { struct fakelb_priv { struct list_head list; - rwlock_t lock; }; static int @@ -79,10 +79,9 @@ static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) { struct fakelb_phy *current_phy = hw->priv; - struct fakelb_priv *fake = current_phy->fake; struct fakelb_phy *phy; - read_lock_bh(&fake->lock); + read_lock_bh(&fakelb_lock); list_for_each_entry(phy, ¤t_phy->fake->list, list) { if (current_phy == phy) continue; @@ -91,7 +90,7 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) current_phy->hw->phy->current_channel) fakelb_hw_deliver(phy, skb); } - read_unlock_bh(&fake->lock); + read_unlock_bh(&fakelb_lock); return 0; } @@ -188,9 +187,9 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) if (err) goto err_reg; - write_lock_bh(&fake->lock); + write_lock_bh(&fakelb_lock); list_add_tail(&phy->list, &fake->list); - write_unlock_bh(&fake->lock); + write_unlock_bh(&fakelb_lock); return 0; @@ -201,9 +200,9 @@ err_reg: static void fakelb_del(struct fakelb_phy *phy) { - write_lock_bh(&phy->fake->lock); + write_lock_bh(&fakelb_lock); list_del(&phy->list); - write_unlock_bh(&phy->fake->lock); + write_unlock_bh(&fakelb_lock); ieee802154_unregister_hw(phy->hw); ieee802154_free_hw(phy->hw); @@ -222,7 +221,6 @@ static int fakelb_probe(struct platform_device *pdev) goto err_alloc; INIT_LIST_HEAD(&priv->list); - rwlock_init(&priv->lock); for (i = 0; i < numlbs; i++) { err = fakelb_add_one(&pdev->dev, priv); -- cgit v1.2.3 From b82b99f16bc207291b14228441cfffbfd23d5f49 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:03 +0200 Subject: fakelb: declare fakelb list static This patch moves the fakelb list of all registered phy's in a static declaration in the fakelb driver. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 43370fb48cf6..c7e7d506224f 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -29,21 +29,17 @@ static int numlbs = 2; static DEFINE_RWLOCK(fakelb_lock); +static LIST_HEAD(fakelb_phys); struct fakelb_phy { struct ieee802154_hw *hw; struct list_head list; - struct fakelb_priv *fake; spinlock_t lock; bool working; }; -struct fakelb_priv { - struct list_head list; -}; - static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) { @@ -82,7 +78,7 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) struct fakelb_phy *phy; read_lock_bh(&fakelb_lock); - list_for_each_entry(phy, ¤t_phy->fake->list, list) { + list_for_each_entry(phy, &fakelb_phys, list) { if (current_phy == phy) continue; @@ -132,7 +128,7 @@ static const struct ieee802154_ops fakelb_ops = { module_param(numlbs, int, 0); MODULE_PARM_DESC(numlbs, " number of pseudo devices"); -static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) +static int fakelb_add_one(struct device *dev) { struct fakelb_phy *phy; int err; @@ -176,9 +172,6 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) /* 950 MHz GFSK 802.15.4d-2009 */ hw->phy->supported.channels[6] |= 0x3ffc00; - INIT_LIST_HEAD(&phy->list); - phy->fake = fake; - spin_lock_init(&phy->lock); hw->parent = dev; @@ -188,7 +181,7 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) goto err_reg; write_lock_bh(&fakelb_lock); - list_add_tail(&phy->list, &fake->list); + list_add_tail(&phy->list, &fakelb_phys); write_unlock_bh(&fakelb_lock); return 0; @@ -210,41 +203,30 @@ static void fakelb_del(struct fakelb_phy *phy) static int fakelb_probe(struct platform_device *pdev) { - struct fakelb_priv *priv; struct fakelb_phy *phy, *tmp; int err = -ENOMEM; int i; - priv = devm_kzalloc(&pdev->dev, sizeof(struct fakelb_priv), - GFP_KERNEL); - if (!priv) - goto err_alloc; - - INIT_LIST_HEAD(&priv->list); - for (i = 0; i < numlbs; i++) { - err = fakelb_add_one(&pdev->dev, priv); + err = fakelb_add_one(&pdev->dev); if (err < 0) goto err_slave; } - platform_set_drvdata(pdev, priv); dev_info(&pdev->dev, "added ieee802154 hardware\n"); return 0; err_slave: - list_for_each_entry_safe(phy, tmp, &priv->list, list) + list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); -err_alloc: return err; } static int fakelb_remove(struct platform_device *pdev) { - struct fakelb_priv *priv = platform_get_drvdata(pdev); struct fakelb_phy *phy, *temp; - list_for_each_entry_safe(phy, temp, &priv->list, list) + list_for_each_entry_safe(phy, temp, &fakelb_phys, list) fakelb_del(phy); return 0; -- cgit v1.2.3 From 6fa2cffe8cf937fc10be362a2dcac8a5965f618e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:04 +0200 Subject: fakelb: move lock out of iteration The list need to be protected while iteration which is need when other list iterates at the same time over this list. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index c7e7d506224f..e1c0195c18aa 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -193,9 +193,7 @@ err_reg: static void fakelb_del(struct fakelb_phy *phy) { - write_lock_bh(&fakelb_lock); list_del(&phy->list); - write_unlock_bh(&fakelb_lock); ieee802154_unregister_hw(phy->hw); ieee802154_free_hw(phy->hw); @@ -217,8 +215,10 @@ static int fakelb_probe(struct platform_device *pdev) return 0; err_slave: + write_lock_bh(&fakelb_lock); list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); + write_unlock_bh(&fakelb_lock); return err; } @@ -226,9 +226,10 @@ static int fakelb_remove(struct platform_device *pdev) { struct fakelb_phy *phy, *temp; + write_lock_bh(&fakelb_lock); list_for_each_entry_safe(phy, temp, &fakelb_phys, list) fakelb_del(phy); - + write_unlock_bh(&fakelb_lock); return 0; } -- cgit v1.2.3 From e369dc8f1aa95cd490e1ab75043dcf50d2190453 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:05 +0200 Subject: fakelb: introduce fakelb ifup phys list This patch introduce a fakelb ifup phys list, which stores all registered phys which are in an operated mode. This will reduce the iterations of non-operated phys while transmit frames. There exists two locks now, one rwlock for the operated interfaces and the spinlock for protecting the list for all registered virtual phys. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 58 ++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index e1c0195c18aa..83957de47243 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -28,16 +28,18 @@ #include static int numlbs = 2; -static DEFINE_RWLOCK(fakelb_lock); + static LIST_HEAD(fakelb_phys); +static DEFINE_SPINLOCK(fakelb_phys_lock); + +static LIST_HEAD(fakelb_ifup_phys); +static DEFINE_RWLOCK(fakelb_ifup_phys_lock); struct fakelb_phy { struct ieee802154_hw *hw; struct list_head list; - - spinlock_t lock; - bool working; + struct list_head list_ifup; }; static int @@ -62,13 +64,9 @@ fakelb_hw_deliver(struct fakelb_phy *phy, struct sk_buff *skb) { struct sk_buff *newskb; - spin_lock(&phy->lock); - if (phy->working) { - newskb = pskb_copy(skb, GFP_ATOMIC); - if (newskb) - ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); - } - spin_unlock(&phy->lock); + newskb = pskb_copy(skb, GFP_ATOMIC); + if (newskb) + ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); } static int @@ -77,8 +75,8 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) struct fakelb_phy *current_phy = hw->priv; struct fakelb_phy *phy; - read_lock_bh(&fakelb_lock); - list_for_each_entry(phy, &fakelb_phys, list) { + read_lock_bh(&fakelb_ifup_phys_lock); + list_for_each_entry(phy, &fakelb_ifup_phys, list_ifup) { if (current_phy == phy) continue; @@ -86,7 +84,7 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) current_phy->hw->phy->current_channel) fakelb_hw_deliver(phy, skb); } - read_unlock_bh(&fakelb_lock); + read_unlock_bh(&fakelb_ifup_phys_lock); return 0; } @@ -94,25 +92,21 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) static int fakelb_hw_start(struct ieee802154_hw *hw) { struct fakelb_phy *phy = hw->priv; - int ret = 0; - spin_lock(&phy->lock); - if (phy->working) - ret = -EBUSY; - else - phy->working = 1; - spin_unlock(&phy->lock); + write_lock_bh(&fakelb_ifup_phys_lock); + list_add(&phy->list_ifup, &fakelb_ifup_phys); + write_unlock_bh(&fakelb_ifup_phys_lock); - return ret; + return 0; } static void fakelb_hw_stop(struct ieee802154_hw *hw) { struct fakelb_phy *phy = hw->priv; - spin_lock(&phy->lock); - phy->working = 0; - spin_unlock(&phy->lock); + write_lock_bh(&fakelb_ifup_phys_lock); + list_del(&phy->list_ifup); + write_unlock_bh(&fakelb_ifup_phys_lock); } static const struct ieee802154_ops fakelb_ops = { @@ -172,17 +166,15 @@ static int fakelb_add_one(struct device *dev) /* 950 MHz GFSK 802.15.4d-2009 */ hw->phy->supported.channels[6] |= 0x3ffc00; - spin_lock_init(&phy->lock); - hw->parent = dev; err = ieee802154_register_hw(hw); if (err) goto err_reg; - write_lock_bh(&fakelb_lock); + spin_lock(&fakelb_phys_lock); list_add_tail(&phy->list, &fakelb_phys); - write_unlock_bh(&fakelb_lock); + spin_unlock(&fakelb_phys_lock); return 0; @@ -215,10 +207,10 @@ static int fakelb_probe(struct platform_device *pdev) return 0; err_slave: - write_lock_bh(&fakelb_lock); + spin_lock(&fakelb_phys_lock); list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); - write_unlock_bh(&fakelb_lock); + spin_unlock(&fakelb_phys_lock); return err; } @@ -226,10 +218,10 @@ static int fakelb_remove(struct platform_device *pdev) { struct fakelb_phy *phy, *temp; - write_lock_bh(&fakelb_lock); + spin_lock(&fakelb_phys_lock); list_for_each_entry_safe(phy, temp, &fakelb_phys, list) fakelb_del(phy); - write_unlock_bh(&fakelb_lock); + spin_unlock(&fakelb_phys_lock); return 0; } -- cgit v1.2.3 From 12da8d97ab3239101077a415c2587bfbf6725216 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:06 +0200 Subject: fakelb: use own channel and page attributes This patch adds an own phy attribute for page and channel into fakelb_phy. The current way is to use the internal mac802154 stored phy pib values which can occur in locking issues while using it inside the driver layer. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 83957de47243..c60837e0df25 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -38,6 +38,9 @@ static DEFINE_RWLOCK(fakelb_ifup_phys_lock); struct fakelb_phy { struct ieee802154_hw *hw; + u8 page; + u8 channel; + struct list_head list; struct list_head list_ifup; }; @@ -54,8 +57,12 @@ fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) static int fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) { - pr_debug("set channel to %d\n", channel); + struct fakelb_phy *phy = hw->priv; + write_lock_bh(&fakelb_ifup_phys_lock); + phy->page = page; + phy->channel = channel; + write_unlock_bh(&fakelb_ifup_phys_lock); return 0; } @@ -80,8 +87,8 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) if (current_phy == phy) continue; - if (phy->hw->phy->current_channel == - current_phy->hw->phy->current_channel) + if (current_phy->page == phy->page && + current_phy->channel == phy->channel) fakelb_hw_deliver(phy, skb); } read_unlock_bh(&fakelb_ifup_phys_lock); -- cgit v1.2.3 From e214a9040a602552d40d0c71cdb38fac8f619cd6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:07 +0200 Subject: fakelb: add virtual phy reset defaults This patch adds reset defaults for the fakelb phy. I used the channel 13 and page 0 which is the same default like at86rf233. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index c60837e0df25..d693a539f8f3 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -173,6 +173,11 @@ static int fakelb_add_one(struct device *dev) /* 950 MHz GFSK 802.15.4d-2009 */ hw->phy->supported.channels[6] |= 0x3ffc00; + ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); + /* fake phy channel 13 as default */ + hw->phy->current_channel = 13; + phy->channel = hw->phy->current_channel; + hw->parent = dev; err = ieee802154_register_hw(hw); -- cgit v1.2.3 From 98be165b4355f750a62ca5ad280e04a135fe9bbd Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:08 +0200 Subject: fakelb: remove fakelb_hw_deliver This patch cleanups the fakelb_hw_deliver function by removing them. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index d693a539f8f3..10e2d27dbed4 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -66,16 +66,6 @@ fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) return 0; } -static void -fakelb_hw_deliver(struct fakelb_phy *phy, struct sk_buff *skb) -{ - struct sk_buff *newskb; - - newskb = pskb_copy(skb, GFP_ATOMIC); - if (newskb) - ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); -} - static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) { @@ -88,8 +78,12 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) continue; if (current_phy->page == phy->page && - current_phy->channel == phy->channel) - fakelb_hw_deliver(phy, skb); + current_phy->channel == phy->channel) { + struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC); + + if (newskb) + ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); + } } read_unlock_bh(&fakelb_ifup_phys_lock); -- cgit v1.2.3 From a09c07a8c89ee910f97d09577ec30b3084fb1d6a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:09 +0200 Subject: fakelb: add support for async xmit handling This patch will add async xmit support for the fakelb driver. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 10e2d27dbed4..8f37ea0fa1f5 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -87,6 +87,7 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) } read_unlock_bh(&fakelb_ifup_phys_lock); + ieee802154_xmit_complete(hw, skb, false); return 0; } @@ -112,7 +113,7 @@ fakelb_hw_stop(struct ieee802154_hw *hw) { static const struct ieee802154_ops fakelb_ops = { .owner = THIS_MODULE, - .xmit_sync = fakelb_hw_xmit, + .xmit_async = fakelb_hw_xmit, .ed = fakelb_hw_ed, .set_channel = fakelb_hw_channel, .start = fakelb_hw_start, -- cgit v1.2.3 From 39572ab30feb92a8d49bf2a59c9a492ba858c008 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:45:10 +0200 Subject: fakelb: cleanup code This patch just cleanups the code at several places. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/fakelb.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 8f37ea0fa1f5..9d0da4ec3e8c 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -45,8 +45,7 @@ struct fakelb_phy { struct list_head list_ifup; }; -static int -fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) +static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) { BUG_ON(!level); *level = 0xbe; @@ -54,8 +53,7 @@ fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) return 0; } -static int -fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) +static int fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) { struct fakelb_phy *phy = hw->priv; @@ -66,11 +64,9 @@ fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) return 0; } -static int -fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) { - struct fakelb_phy *current_phy = hw->priv; - struct fakelb_phy *phy; + struct fakelb_phy *current_phy = hw->priv, *phy; read_lock_bh(&fakelb_ifup_phys_lock); list_for_each_entry(phy, &fakelb_ifup_phys, list_ifup) { @@ -91,8 +87,8 @@ fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) return 0; } -static int -fakelb_hw_start(struct ieee802154_hw *hw) { +static int fakelb_hw_start(struct ieee802154_hw *hw) +{ struct fakelb_phy *phy = hw->priv; write_lock_bh(&fakelb_ifup_phys_lock); @@ -102,8 +98,8 @@ fakelb_hw_start(struct ieee802154_hw *hw) { return 0; } -static void -fakelb_hw_stop(struct ieee802154_hw *hw) { +static void fakelb_hw_stop(struct ieee802154_hw *hw) +{ struct fakelb_phy *phy = hw->priv; write_lock_bh(&fakelb_ifup_phys_lock); @@ -126,9 +122,9 @@ MODULE_PARM_DESC(numlbs, " number of pseudo devices"); static int fakelb_add_one(struct device *dev) { + struct ieee802154_hw *hw; struct fakelb_phy *phy; int err; - struct ieee802154_hw *hw; hw = ieee802154_alloc_hw(sizeof(*phy), &fakelb_ops); if (!hw) @@ -201,8 +197,7 @@ static void fakelb_del(struct fakelb_phy *phy) static int fakelb_probe(struct platform_device *pdev) { struct fakelb_phy *phy, *tmp; - int err = -ENOMEM; - int i; + int err, i; for (i = 0; i < numlbs; i++) { err = fakelb_add_one(&pdev->dev); @@ -223,10 +218,10 @@ err_slave: static int fakelb_remove(struct platform_device *pdev) { - struct fakelb_phy *phy, *temp; + struct fakelb_phy *phy, *tmp; spin_lock(&fakelb_phys_lock); - list_for_each_entry_safe(phy, temp, &fakelb_phys, list) + list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) fakelb_del(phy); spin_unlock(&fakelb_phys_lock); return 0; -- cgit v1.2.3 From 179655fcd2f40edeae515da1f4361c7ddc56b8ed Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 May 2015 09:27:03 +0200 Subject: at86rf230: add missing cca ed level values This patch add missing values for at86rf212 ed level values. Currently there are 15 values and the register setting supports 16 different ed level values. Signed-off-by: Alexander Aring Reported-by: Craig Younkins Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index d417ceb67626..2f25a5ed8247 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -892,12 +892,12 @@ static const s32 at86rf23x_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = { static const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = { -10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, - -8000, -7800, -7600, -7400, -7200, + -8000, -7800, -7600, -7400, -7200, -7000, }; static const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = { -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000, - -7800, -7600, -7400, -7200, -7000, + -7800, -7600, -7400, -7200, -7000, -6800, }; static inline int -- cgit v1.2.3 From 33a238ae65cee561b3eb78694a41cd3e196fe59c Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Thu, 21 May 2015 16:51:35 +0200 Subject: ieee802154/atusb: Warn about outdated device firmware. Together with mainlining the driver we released a first public binary version of the device firmware. This is version 0.2. With this change we warn users who run outdated versions of the firmware. While we have not seen problems with it yet (thus no error, but a warning only) it would be better to run the released and tested firmware. You can find released versions here: http://downloads.qi-hardware.com/people/werner/wpan/web/ Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index ea1259ef8508..9d07dd720bbb 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -469,6 +469,12 @@ static int atusb_get_and_show_revision(struct atusb *atusb) dev_info(&usb_dev->dev, "Firmware: major: %u, minor: %u, hardware type: %u\n", buffer[0], buffer[1], buffer[2]); + if (buffer[0] == 0 && buffer[1] < 2) { + dev_info(&usb_dev->dev, + "Firmware version (%u.%u) is predates our first public release.", + buffer[0], buffer[1]); + dev_info(&usb_dev->dev, "Please update to version 0.2 or newer"); + } return ret; } -- cgit v1.2.3 From f1a71886c59f1d981d3848c744e617d2f7e4149e Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Thu, 21 May 2015 16:51:36 +0200 Subject: ieee802154/atusb: Mark driver as AACK enabled in hardware. Since firmware version 0.2 we use AACK handling directly in the firmware. Inform the stack that the hardware supports and uses it. Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 9d07dd720bbb..eef1d8aa0269 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -568,7 +568,8 @@ static int atusb_probe(struct usb_interface *interface, goto fail; hw->parent = &usb_dev->dev; - hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT; + hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | + IEEE802154_HW_AACK; hw->phy->current_page = 0; hw->phy->current_channel = 11; /* reset default */ -- cgit v1.2.3 From 2d8cbd31dd5d4fe7825e1ab88f39c283849db946 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Thu, 21 May 2015 16:51:37 +0200 Subject: ieee802154/atusb: Set default ed level to 0xbe like the rest of these drivers Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index eef1d8aa0269..1e18774240b2 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -365,8 +365,8 @@ static int atusb_channel(struct ieee802154_hw *hw, u8 page, u8 channel) static int atusb_ed(struct ieee802154_hw *hw, u8 *level) { - /* @@@ not used by the stack yet */ - *level = 0; + BUG_ON(!level); + *level = 0xbe; return 0; } -- cgit v1.2.3 From 7f6e63631dbd7fd6689b4ee301d0eea0f34c5535 Mon Sep 17 00:00:00 2001 From: Chan-yeol Park Date: Thu, 21 May 2015 11:24:27 +0900 Subject: Bluetooth: btusb: Support QCA61x4 ROME v2.0 The previous commit(3267c88) missed QCA61x4 ROME v2.0 info on Samsung so its BT is not activated and the below message is shown. [ 8.009638] usb 1-1: New USB device found, idVendor=0cf3, idProduct=e300 [ 8.012637] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [ 8.102901] Bluetooth: hci0: don't support firmware rome 0x200 This patch adds QCA61x4 ROME v2.0 info in qca_devices_table[], and is verified on Samsung with the firmware provided by Kim, Ben Young Tae . T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e300 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Chan-yeol Park Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b9f282112153..c334620c07b3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2382,6 +2382,7 @@ struct qca_device_info { static const struct qca_device_info qca_devices_table[] = { { 0x00000100, 20, 4, 10 }, /* Rome 1.0 */ { 0x00000101, 20, 4, 10 }, /* Rome 1.1 */ + { 0x00000200, 28, 4, 18 }, /* Rome 2.0 */ { 0x00000201, 28, 4, 18 }, /* Rome 2.1 */ { 0x00000300, 28, 4, 18 }, /* Rome 3.0 */ { 0x00000302, 28, 4, 18 }, /* Rome 3.2 */ -- cgit v1.2.3 From 917a33379258c137324cb9204e2f2f6ed8dc2b78 Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Mon, 25 May 2015 23:53:40 +0530 Subject: Bluetooth: btusb: Change 1 to true in bool type variable assignment The reset is a bool type variable. So assigning true to reset instead of 1. Signed-off-by: Shailendra Verma Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c334620c07b3..8ff0e162341d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -38,7 +38,7 @@ static bool disable_scofix; static bool force_scofix; -static bool reset = 1; +static bool reset = true; static struct usb_driver btusb_driver; -- cgit v1.2.3 From bff6b89f86f5f4884e844300c5dc729b3d405681 Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 26 May 2015 00:00:57 +0530 Subject: Bluetooth: hci_uart: Change 1 to true for bool type variables assignments The variables txcrc and hciextn are bool type. So assigning true instead of 1. Signed-off-by: Shailendra Verma Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index dc8e3d4356a0..fc0056a28b81 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -47,8 +47,8 @@ #include "hci_uart.h" -static bool txcrc = 1; -static bool hciextn = 1; +static bool txcrc = true; +static bool hciextn = true; #define BCSP_TXWINSIZE 4 -- cgit v1.2.3 From 04b8c8143d46453a443ac32bfcd76ec952605765 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 21 May 2015 08:23:50 -0600 Subject: Bluetooth: btusb: fix Realtek suspend/resume Realtek btusb devices don't currently work after suspend/resume because the updated firmware is quietly lost - the USB hub doesn't notice any status change upon resume, but some kind of reset has definitely happened as the LMP subversion has reverted to its original value. Set the reset_resume flag to trigger probe and upload the new firmware again. Like the vendor code, I assume this is not needed when the device is selected as a wakeup source and hence will retain power during suspend. On the 2 products I have to hand, when trying this configuration the hardware seems unable to keep the device powered up during suspend. The USB hub then detects a status change on resume and does a reset, so we do not end up in broken state. Signed-off-by: Daniel Drake Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8ff0e162341d..a92811468542 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -328,6 +328,7 @@ static const struct usb_device_id blacklist_table[] = { #define BTUSB_FIRMWARE_LOADED 7 #define BTUSB_FIRMWARE_FAILED 8 #define BTUSB_BOOTING 9 +#define BTUSB_RESET_RESUME 10 struct btusb_data { struct hci_dev *hdev; @@ -2767,8 +2768,15 @@ static int btusb_probe(struct usb_interface *intf, } #ifdef CONFIG_BT_HCIBTUSB_RTL - if (id->driver_info & BTUSB_REALTEK) + if (id->driver_info & BTUSB_REALTEK) { hdev->setup = btrtl_setup_realtek; + + /* Realtek devices lose their updated firmware over suspend, + * but the USB hub doesn't notice any status change. + * Explicitly request a device reset on resume. + */ + set_bit(BTUSB_RESET_RESUME, &data->flags); + } #endif if (id->driver_info & BTUSB_AMP) { @@ -2901,6 +2909,14 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); + /* Optionally request a device reset on resume, but only when + * wakeups are disabled. If wakeups are enabled we assume the + * device will stay powered up throughout suspend. + */ + if (test_bit(BTUSB_RESET_RESUME, &data->flags) && + !device_may_wakeup(&data->udev->dev)) + data->udev->reset_resume = 1; + return 0; } -- cgit v1.2.3 From b5a61c306b0dddb28e3a3ab5d782c73e5f665497 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 27 May 2015 14:11:28 +0200 Subject: atusb: add support for at86rf230 This patch adds support for the at86rf230 version check which is used by the rzusb stick. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/atusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 1e18774240b2..5b6bb9adf9ae 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -515,7 +515,7 @@ static int atusb_get_and_show_chip(struct atusb *atusb) man_id_1, man_id_0); goto fail; } - if (part_num != 3) { + if (part_num != 3 && part_num != 2) { dev_err(&usb_dev->dev, "unexpected transceiver, part 0x%02x version 0x%02x\n", part_num, version_num); -- cgit v1.2.3