You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2015-08-16 Here's what's likely the last bluetooth-next pull request for 4.3: - 6lowpan/802.15.4 refactoring, cleanups & fixes - Document 6lowpan netdev usage in Documentation/networking/6lowpan.txt - Support for UART based QCA Bluetooth controllers - Power management support for Broeadcom Bluetooth controllers - Change LE connection initiation to always use passive scanning first - Support for new Silicon Wave USB ID Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
|
||||
Netdev private dataroom for 6lowpan interfaces:
|
||||
|
||||
All 6lowpan able net devices, means all interfaces with ARPHRD_6LOWPAN,
|
||||
must have "struct lowpan_priv" placed at beginning of netdev_priv.
|
||||
|
||||
The priv_size of each interface should be calculate by:
|
||||
|
||||
dev->priv_size = LOWPAN_PRIV_SIZE(LL_6LOWPAN_PRIV_DATA);
|
||||
|
||||
Where LL_PRIV_6LOWPAN_DATA is sizeof linklayer 6lowpan private data struct.
|
||||
To access the LL_PRIV_6LOWPAN_DATA structure you can cast:
|
||||
|
||||
lowpan_priv(dev)-priv;
|
||||
|
||||
to your LL_6LOWPAN_PRIV_DATA structure.
|
||||
|
||||
Before registering the lowpan netdev interface you must run:
|
||||
|
||||
lowpan_netdev_setup(dev, LOWPAN_LLTYPE_FOOBAR);
|
||||
|
||||
wheres LOWPAN_LLTYPE_FOOBAR is a define for your 6LoWPAN linklayer type of
|
||||
enum lowpan_lltypes.
|
||||
|
||||
Example to evaluate the private usually you can do:
|
||||
|
||||
static inline sturct lowpan_priv_foobar *
|
||||
lowpan_foobar_priv(struct net_device *dev)
|
||||
{
|
||||
return (sturct lowpan_priv_foobar *)lowpan_priv(dev)->priv;
|
||||
}
|
||||
|
||||
switch (dev->type) {
|
||||
case ARPHRD_6LOWPAN:
|
||||
lowpan_priv = lowpan_priv(dev);
|
||||
/* do great stuff which is ARPHRD_6LOWPAN related */
|
||||
switch (lowpan_priv->lltype) {
|
||||
case LOWPAN_LLTYPE_FOOBAR:
|
||||
/* do 802.15.4 6LoWPAN handling here */
|
||||
lowpan_foobar_priv(dev)->bar = foo;
|
||||
break;
|
||||
...
|
||||
}
|
||||
break;
|
||||
...
|
||||
}
|
||||
|
||||
In case of generic 6lowpan branch ("net/6lowpan") you can remove the check
|
||||
on ARPHRD_6LOWPAN, because you can be sure that these function are called
|
||||
by ARPHRD_6LOWPAN interfaces.
|
||||
@@ -158,6 +158,7 @@ L: linux-wpan@vger.kernel.org
|
||||
S: Maintained
|
||||
F: net/6lowpan/
|
||||
F: include/net/6lowpan.h
|
||||
F: Documentation/networking/6lowpan.txt
|
||||
|
||||
6PACK NETWORK DRIVER FOR AX.25
|
||||
M: Andreas Koensgen <ajk@comnets.uni-bremen.de>
|
||||
|
||||
@@ -13,6 +13,10 @@ config BT_RTL
|
||||
tristate
|
||||
select FW_LOADER
|
||||
|
||||
config BT_QCA
|
||||
tristate
|
||||
select FW_LOADER
|
||||
|
||||
config BT_HCIBTUSB
|
||||
tristate "HCI USB driver"
|
||||
depends on USB
|
||||
@@ -151,6 +155,19 @@ config BT_HCIUART_BCM
|
||||
|
||||
Say Y here to compile support for Broadcom protocol.
|
||||
|
||||
config BT_HCIUART_QCA
|
||||
bool "Qualcomm Atheros protocol support"
|
||||
depends on BT_HCIUART
|
||||
select BT_HCIUART_H4
|
||||
select BT_QCA
|
||||
help
|
||||
The Qualcomm Atheros protocol supports HCI In-Band Sleep feature
|
||||
over serial port interface(H4) between controller and host.
|
||||
This protocol is required for UART clock control for QCA Bluetooth
|
||||
devices.
|
||||
|
||||
Say Y here to compile support for QCA protocol.
|
||||
|
||||
config BT_HCIBCM203X
|
||||
tristate "HCI BCM203x USB driver"
|
||||
depends on USB
|
||||
|
||||
@@ -22,6 +22,7 @@ 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
|
||||
obj-$(CONFIG_BT_QCA) += btqca.o
|
||||
|
||||
btmrvl-y := btmrvl_main.o
|
||||
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
|
||||
@@ -34,6 +35,7 @@ hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o
|
||||
hci_uart-objs := $(hci_uart-y)
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
||||
@@ -1071,8 +1071,6 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
|
||||
}
|
||||
}
|
||||
|
||||
sdio_release_host(card->func);
|
||||
|
||||
/*
|
||||
* winner or not, with this test the FW synchronizes when the
|
||||
* module can continue its initialization
|
||||
@@ -1082,6 +1080,8 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
sdio_release_host(card->func);
|
||||
|
||||
return 0;
|
||||
|
||||
done:
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Bluetooth supports for Qualcomm Atheros chips
|
||||
*
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "btqca.h"
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
struct rome_version *ver;
|
||||
char cmd;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("%s: ROME Patch Version Request", hdev->name);
|
||||
|
||||
cmd = EDL_PATCH_VER_REQ_CMD;
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
|
||||
&cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name,
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*edl) + sizeof(*ver)) {
|
||||
BT_ERR("%s: Version size mismatch len %d", hdev->name,
|
||||
skb->len);
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
edl = (struct edl_event_hdr *)(skb->data);
|
||||
if (!edl || !edl->data) {
|
||||
BT_ERR("%s: TLV with no header or no data", hdev->name);
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
|
||||
edl->rtype != EDL_APP_VER_RES_EVT) {
|
||||
BT_ERR("%s: Wrong packet received %d %d", hdev->name,
|
||||
edl->cresp, edl->rtype);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ver = (struct rome_version *)(edl->data);
|
||||
|
||||
BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id));
|
||||
BT_DBG("%s: Patch :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver));
|
||||
BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver));
|
||||
BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id));
|
||||
|
||||
/* ROME chipset version can be decided by patch and SoC
|
||||
* version, combination with upper 2 bytes from SoC
|
||||
* and lower 2 bytes from patch will be used.
|
||||
*/
|
||||
*rome_version = (le32_to_cpu(ver->soc_id) << 16) |
|
||||
(le16_to_cpu(ver->rome_ver) & 0x0000ffff);
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rome_reset(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s: ROME HCI_RESET", hdev->name);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
BT_ERR("%s: Reset failed (%d)", hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rome_tlv_check_data(struct rome_config *config,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
const u8 *data;
|
||||
u32 type_len;
|
||||
u16 tag_id, tag_len;
|
||||
int idx, length;
|
||||
struct tlv_type_hdr *tlv;
|
||||
struct tlv_type_patch *tlv_patch;
|
||||
struct tlv_type_nvm *tlv_nvm;
|
||||
|
||||
tlv = (struct tlv_type_hdr *)fw->data;
|
||||
|
||||
type_len = le32_to_cpu(tlv->type_len);
|
||||
length = (type_len >> 8) & 0x00ffffff;
|
||||
|
||||
BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
|
||||
BT_DBG("Length\t\t : %d bytes", length);
|
||||
|
||||
switch (config->type) {
|
||||
case TLV_TYPE_PATCH:
|
||||
tlv_patch = (struct tlv_type_patch *)tlv->data;
|
||||
BT_DBG("Total Length\t\t : %d bytes",
|
||||
le32_to_cpu(tlv_patch->total_size));
|
||||
BT_DBG("Patch Data Length\t : %d bytes",
|
||||
le32_to_cpu(tlv_patch->data_length));
|
||||
BT_DBG("Signing Format Version : 0x%x",
|
||||
tlv_patch->format_version);
|
||||
BT_DBG("Signature Algorithm\t : 0x%x",
|
||||
tlv_patch->signature);
|
||||
BT_DBG("Reserved\t\t : 0x%x",
|
||||
le16_to_cpu(tlv_patch->reserved1));
|
||||
BT_DBG("Product ID\t\t : 0x%04x",
|
||||
le16_to_cpu(tlv_patch->product_id));
|
||||
BT_DBG("Rom Build Version\t : 0x%04x",
|
||||
le16_to_cpu(tlv_patch->rom_build));
|
||||
BT_DBG("Patch Version\t\t : 0x%04x",
|
||||
le16_to_cpu(tlv_patch->patch_version));
|
||||
BT_DBG("Reserved\t\t : 0x%x",
|
||||
le16_to_cpu(tlv_patch->reserved2));
|
||||
BT_DBG("Patch Entry Address\t : 0x%x",
|
||||
le32_to_cpu(tlv_patch->entry));
|
||||
break;
|
||||
|
||||
case TLV_TYPE_NVM:
|
||||
idx = 0;
|
||||
data = tlv->data;
|
||||
while (idx < length) {
|
||||
tlv_nvm = (struct tlv_type_nvm *)(data + idx);
|
||||
|
||||
tag_id = le16_to_cpu(tlv_nvm->tag_id);
|
||||
tag_len = le16_to_cpu(tlv_nvm->tag_len);
|
||||
|
||||
/* Update NVM tags as needed */
|
||||
switch (tag_id) {
|
||||
case EDL_TAG_ID_HCI:
|
||||
/* HCI transport layer parameters
|
||||
* enabling software inband sleep
|
||||
* onto controller side.
|
||||
*/
|
||||
tlv_nvm->data[0] |= 0x80;
|
||||
|
||||
/* UART Baud Rate */
|
||||
tlv_nvm->data[2] = config->user_baud_rate;
|
||||
|
||||
break;
|
||||
|
||||
case EDL_TAG_ID_DEEP_SLEEP:
|
||||
/* Sleep enable mask
|
||||
* enabling deep sleep feature on controller.
|
||||
*/
|
||||
tlv_nvm->data[0] |= 0x01;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Unknown TLV type %d", config->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
|
||||
const u8 *data)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
struct tlv_seg_resp *tlv_resp;
|
||||
u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2];
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size);
|
||||
|
||||
cmd[0] = EDL_PATCH_TLV_REQ_CMD;
|
||||
cmd[1] = seg_size;
|
||||
memcpy(cmd + 2, data, seg_size);
|
||||
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd,
|
||||
HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) {
|
||||
BT_ERR("%s: TLV response size mismatch", hdev->name);
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
edl = (struct edl_event_hdr *)(skb->data);
|
||||
if (!edl || !edl->data) {
|
||||
BT_ERR("%s: TLV with no header or no data", hdev->name);
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tlv_resp = (struct tlv_seg_resp *)(edl->data);
|
||||
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
|
||||
edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) {
|
||||
BT_ERR("%s: TLV with error stat 0x%x rtype 0x%x (0x%x)",
|
||||
hdev->name, edl->cresp, edl->rtype, tlv_resp->result);
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rome_tlv_download_request(struct hci_dev *hdev,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
const u8 *buffer, *data;
|
||||
int total_segment, remain_size;
|
||||
int ret, i;
|
||||
|
||||
if (!fw || !fw->data)
|
||||
return -EINVAL;
|
||||
|
||||
total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT;
|
||||
remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT;
|
||||
|
||||
BT_DBG("%s: Total segment num %d remain size %d total size %zu",
|
||||
hdev->name, total_segment, remain_size, fw->size);
|
||||
|
||||
data = fw->data;
|
||||
for (i = 0; i < total_segment; i++) {
|
||||
buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT;
|
||||
ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT,
|
||||
buffer);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (remain_size) {
|
||||
buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
|
||||
ret = rome_tlv_send_segment(hdev, total_segment, remain_size,
|
||||
buffer);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rome_download_firmware(struct hci_dev *hdev,
|
||||
struct rome_config *config)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname);
|
||||
|
||||
ret = request_firmware(&fw, config->fwname, &hdev->dev);
|
||||
if (ret) {
|
||||
BT_ERR("%s: Failed to request file: %s (%d)", hdev->name,
|
||||
config->fwname, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rome_tlv_check_data(config, fw);
|
||||
|
||||
ret = rome_tlv_download_request(hdev, fw);
|
||||
if (ret) {
|
||||
BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
|
||||
config->fwname, ret);
|
||||
}
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 cmd[9];
|
||||
int err;
|
||||
|
||||
cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
|
||||
cmd[1] = 0x02; /* TAG ID */
|
||||
cmd[2] = sizeof(bdaddr_t); /* size */
|
||||
memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd,
|
||||
HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
BT_ERR("%s: Change address command failed (%d)",
|
||||
hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
|
||||
|
||||
int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate)
|
||||
{
|
||||
u32 rome_ver = 0;
|
||||
struct rome_config config;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s: ROME setup on UART", hdev->name);
|
||||
|
||||
config.user_baud_rate = baudrate;
|
||||
|
||||
/* Get ROME version information */
|
||||
err = rome_patch_ver_req(hdev, &rome_ver);
|
||||
if (err < 0 || rome_ver == 0) {
|
||||
BT_ERR("%s: Failed to get version 0x%x", hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_INFO("%s: ROME controller version 0x%08x", hdev->name, rome_ver);
|
||||
|
||||
/* Download rampatch file */
|
||||
config.type = TLV_TYPE_PATCH;
|
||||
snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin",
|
||||
rome_ver);
|
||||
err = rome_download_firmware(hdev, &config);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to download patch (%d)", hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Download NVM configuration */
|
||||
config.type = TLV_TYPE_NVM;
|
||||
snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin",
|
||||
rome_ver);
|
||||
err = rome_download_firmware(hdev, &config);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Perform HCI reset */
|
||||
err = rome_reset(hdev);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_INFO("%s: ROME setup on UART is completed", hdev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qca_uart_setup_rome);
|
||||
|
||||
MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>");
|
||||
MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Bluetooth supports for Qualcomm Atheros ROME chips
|
||||
*
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#define EDL_PATCH_CMD_OPCODE (0xFC00)
|
||||
#define EDL_NVM_ACCESS_OPCODE (0xFC0B)
|
||||
#define EDL_PATCH_CMD_LEN (1)
|
||||
#define EDL_PATCH_VER_REQ_CMD (0x19)
|
||||
#define EDL_PATCH_TLV_REQ_CMD (0x1E)
|
||||
#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01)
|
||||
#define MAX_SIZE_PER_TLV_SEGMENT (243)
|
||||
|
||||
#define EDL_CMD_REQ_RES_EVT (0x00)
|
||||
#define EDL_PATCH_VER_RES_EVT (0x19)
|
||||
#define EDL_APP_VER_RES_EVT (0x02)
|
||||
#define EDL_TVL_DNLD_RES_EVT (0x04)
|
||||
#define EDL_CMD_EXE_STATUS_EVT (0x00)
|
||||
#define EDL_SET_BAUDRATE_RSP_EVT (0x92)
|
||||
#define EDL_NVM_ACCESS_CODE_EVT (0x0B)
|
||||
|
||||
#define EDL_TAG_ID_HCI (17)
|
||||
#define EDL_TAG_ID_DEEP_SLEEP (27)
|
||||
|
||||
enum qca_bardrate {
|
||||
QCA_BAUDRATE_115200 = 0,
|
||||
QCA_BAUDRATE_57600,
|
||||
QCA_BAUDRATE_38400,
|
||||
QCA_BAUDRATE_19200,
|
||||
QCA_BAUDRATE_9600,
|
||||
QCA_BAUDRATE_230400,
|
||||
QCA_BAUDRATE_250000,
|
||||
QCA_BAUDRATE_460800,
|
||||
QCA_BAUDRATE_500000,
|
||||
QCA_BAUDRATE_720000,
|
||||
QCA_BAUDRATE_921600,
|
||||
QCA_BAUDRATE_1000000,
|
||||
QCA_BAUDRATE_1250000,
|
||||
QCA_BAUDRATE_2000000,
|
||||
QCA_BAUDRATE_3000000,
|
||||
QCA_BAUDRATE_4000000,
|
||||
QCA_BAUDRATE_1600000,
|
||||
QCA_BAUDRATE_3200000,
|
||||
QCA_BAUDRATE_3500000,
|
||||
QCA_BAUDRATE_AUTO = 0xFE,
|
||||
QCA_BAUDRATE_RESERVED
|
||||
};
|
||||
|
||||
enum rome_tlv_type {
|
||||
TLV_TYPE_PATCH = 1,
|
||||
TLV_TYPE_NVM
|
||||
};
|
||||
|
||||
struct rome_config {
|
||||
u8 type;
|
||||
char fwname[64];
|
||||
uint8_t user_baud_rate;
|
||||
};
|
||||
|
||||
struct edl_event_hdr {
|
||||
__u8 cresp;
|
||||
__u8 rtype;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct rome_version {
|
||||
__le32 product_id;
|
||||
__le16 patch_ver;
|
||||
__le16 rome_ver;
|
||||
__le32 soc_id;
|
||||
} __packed;
|
||||
|
||||
struct tlv_seg_resp {
|
||||
__u8 result;
|
||||
} __packed;
|
||||
|
||||
struct tlv_type_patch {
|
||||
__le32 total_size;
|
||||
__le32 data_length;
|
||||
__u8 format_version;
|
||||
__u8 signature;
|
||||
__le16 reserved1;
|
||||
__le16 product_id;
|
||||
__le16 rom_build;
|
||||
__le16 patch_version;
|
||||
__le16 reserved2;
|
||||
__le32 entry;
|
||||
} __packed;
|
||||
|
||||
struct tlv_type_nvm {
|
||||
__le16 tag_id;
|
||||
__le16 tag_len;
|
||||
__le32 reserve1;
|
||||
__le32 reserve2;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct tlv_type_hdr {
|
||||
__le32 type_len;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_QCA)
|
||||
|
||||
int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate);
|
||||
|
||||
#else
|
||||
|
||||
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -322,6 +322,9 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },
|
||||
|
||||
/* Silicon Wave based devices */
|
||||
{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
||||
+309
-3
@@ -25,6 +25,12 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
@@ -32,11 +38,37 @@
|
||||
#include "btbcm.h"
|
||||
#include "hci_uart.h"
|
||||
|
||||
struct bcm_data {
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff_head txq;
|
||||
struct bcm_device {
|
||||
struct list_head list;
|
||||
|
||||
struct platform_device *pdev;
|
||||
|
||||
const char *name;
|
||||
struct gpio_desc *device_wakeup;
|
||||
struct gpio_desc *shutdown;
|
||||
|
||||
struct clk *clk;
|
||||
bool clk_enabled;
|
||||
|
||||
u32 init_speed;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct hci_uart *hu;
|
||||
bool is_suspended; /* suspend/resume flag */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcm_data {
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff_head txq;
|
||||
|
||||
struct bcm_device *dev;
|
||||
};
|
||||
|
||||
/* List of BCM BT UART devices */
|
||||
static DEFINE_SPINLOCK(bcm_device_list_lock);
|
||||
static LIST_HEAD(bcm_device_list);
|
||||
|
||||
static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
|
||||
{
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
@@ -86,9 +118,41 @@ static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bcm_device_exists should be protected by bcm_device_list_lock */
|
||||
static bool bcm_device_exists(struct bcm_device *device)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, &bcm_device_list) {
|
||||
struct bcm_device *dev = list_entry(p, struct bcm_device, list);
|
||||
|
||||
if (device == dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
|
||||
{
|
||||
if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled)
|
||||
clk_enable(dev->clk);
|
||||
|
||||
gpiod_set_value_cansleep(dev->shutdown, powered);
|
||||
gpiod_set_value_cansleep(dev->device_wakeup, powered);
|
||||
|
||||
if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled)
|
||||
clk_disable(dev->clk);
|
||||
|
||||
dev->clk_enabled = powered;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_open(struct hci_uart *hu)
|
||||
{
|
||||
struct bcm_data *bcm;
|
||||
struct list_head *p;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
@@ -99,6 +163,30 @@ static int bcm_open(struct hci_uart *hu)
|
||||
skb_queue_head_init(&bcm->txq);
|
||||
|
||||
hu->priv = bcm;
|
||||
|
||||
spin_lock(&bcm_device_list_lock);
|
||||
list_for_each(p, &bcm_device_list) {
|
||||
struct bcm_device *dev = list_entry(p, struct bcm_device, list);
|
||||
|
||||
/* Retrieve saved bcm_device based on parent of the
|
||||
* platform device (saved during device probe) and
|
||||
* parent of tty device used by hci_uart
|
||||
*/
|
||||
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
|
||||
bcm->dev = dev;
|
||||
hu->init_speed = dev->init_speed;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
dev->hu = hu;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bcm->dev)
|
||||
bcm_gpio_set_power(bcm->dev, true);
|
||||
|
||||
spin_unlock(&bcm_device_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -108,6 +196,16 @@ static int bcm_close(struct hci_uart *hu)
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
/* Protect bcm->dev against removal of the device or driver */
|
||||
spin_lock(&bcm_device_list_lock);
|
||||
if (bcm_device_exists(bcm->dev)) {
|
||||
bcm_gpio_set_power(bcm->dev, false);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
bcm->dev->hu = NULL;
|
||||
#endif
|
||||
}
|
||||
spin_unlock(&bcm_device_list_lock);
|
||||
|
||||
skb_queue_purge(&bcm->txq);
|
||||
kfree_skb(bcm->rx_skb);
|
||||
kfree(bcm);
|
||||
@@ -232,6 +330,188 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
|
||||
return skb_dequeue(&bcm->txq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* Platform suspend callback */
|
||||
static int bcm_suspend(struct device *dev)
|
||||
{
|
||||
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
|
||||
|
||||
BT_DBG("suspend (%p): is_suspended %d", bdev, bdev->is_suspended);
|
||||
|
||||
if (!bdev->is_suspended) {
|
||||
hci_uart_set_flow_control(bdev->hu, true);
|
||||
|
||||
/* Once this callback returns, driver suspends BT via GPIO */
|
||||
bdev->is_suspended = true;
|
||||
}
|
||||
|
||||
/* Suspend the device */
|
||||
if (bdev->device_wakeup) {
|
||||
gpiod_set_value(bdev->device_wakeup, false);
|
||||
BT_DBG("suspend, delaying 15 ms");
|
||||
mdelay(15);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Platform resume callback */
|
||||
static int bcm_resume(struct device *dev)
|
||||
{
|
||||
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
|
||||
|
||||
BT_DBG("resume (%p): is_suspended %d", bdev, bdev->is_suspended);
|
||||
|
||||
if (bdev->device_wakeup) {
|
||||
gpiod_set_value(bdev->device_wakeup, true);
|
||||
BT_DBG("resume, delaying 15 ms");
|
||||
mdelay(15);
|
||||
}
|
||||
|
||||
/* When this callback executes, the device has woken up already */
|
||||
if (bdev->is_suspended) {
|
||||
bdev->is_suspended = false;
|
||||
|
||||
hci_uart_set_flow_control(bdev->hu, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct acpi_gpio_params device_wakeup_gpios = { 0, 0, false };
|
||||
static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
|
||||
|
||||
static const struct acpi_gpio_mapping acpi_bcm_default_gpios[] = {
|
||||
{ "device-wakeup-gpios", &device_wakeup_gpios, 1 },
|
||||
{ "shutdown-gpios", &shutdown_gpios, 1 },
|
||||
{ },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static int bcm_resource(struct acpi_resource *ares, void *data)
|
||||
{
|
||||
struct bcm_device *dev = data;
|
||||
|
||||
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
|
||||
struct acpi_resource_uart_serialbus *sb;
|
||||
|
||||
sb = &ares->data.uart_serial_bus;
|
||||
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_UART)
|
||||
dev->init_speed = sb->default_baud_rate;
|
||||
}
|
||||
|
||||
/* Always tell the ACPI core to skip this resource */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bcm_acpi_probe(struct bcm_device *dev)
|
||||
{
|
||||
struct platform_device *pdev = dev->pdev;
|
||||
const struct acpi_device_id *id;
|
||||
struct acpi_device *adev;
|
||||
LIST_HEAD(resources);
|
||||
int ret;
|
||||
|
||||
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
/* Retrieve GPIO data */
|
||||
dev->name = dev_name(&pdev->dev);
|
||||
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
||||
acpi_bcm_default_gpios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
|
||||
dev->device_wakeup = devm_gpiod_get_optional(&pdev->dev,
|
||||
"device-wakeup",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(dev->device_wakeup))
|
||||
return PTR_ERR(dev->device_wakeup);
|
||||
|
||||
dev->shutdown = devm_gpiod_get_optional(&pdev->dev, "shutdown",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(dev->shutdown))
|
||||
return PTR_ERR(dev->shutdown);
|
||||
|
||||
/* Make sure at-least one of the GPIO is defined and that
|
||||
* a name is specified for this instance
|
||||
*/
|
||||
if ((!dev->device_wakeup && !dev->shutdown) || !dev->name) {
|
||||
dev_err(&pdev->dev, "invalid platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Retrieve UART ACPI info */
|
||||
adev = ACPI_COMPANION(&dev->pdev->dev);
|
||||
if (!adev)
|
||||
return 0;
|
||||
|
||||
acpi_dev_get_resources(adev, &resources, bcm_resource, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int bcm_acpi_probe(struct bcm_device *dev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int bcm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm_device *dev;
|
||||
struct acpi_device_id *pdata = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->pdev = pdev;
|
||||
|
||||
if (ACPI_HANDLE(&pdev->dev)) {
|
||||
ret = bcm_acpi_probe(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (pdata) {
|
||||
dev->name = pdata->id;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
dev_info(&pdev->dev, "%s device registered.\n", dev->name);
|
||||
|
||||
/* Place this instance on the device list */
|
||||
spin_lock(&bcm_device_list_lock);
|
||||
list_add_tail(&dev->list, &bcm_device_list);
|
||||
spin_unlock(&bcm_device_list_lock);
|
||||
|
||||
bcm_gpio_set_power(dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
spin_lock(&bcm_device_list_lock);
|
||||
list_del(&dev->list);
|
||||
spin_unlock(&bcm_device_list_lock);
|
||||
|
||||
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
|
||||
|
||||
dev_info(&pdev->dev, "%s device unregistered.\n", dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hci_uart_proto bcm_proto = {
|
||||
.id = HCI_UART_BCM,
|
||||
.name = "BCM",
|
||||
@@ -247,12 +527,38 @@ static const struct hci_uart_proto bcm_proto = {
|
||||
.dequeue = bcm_dequeue,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id bcm_acpi_match[] = {
|
||||
{ "BCM2E39", 0 },
|
||||
{ "BCM2E67", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
|
||||
#endif
|
||||
|
||||
/* Platform suspend and resume callbacks */
|
||||
static SIMPLE_DEV_PM_OPS(bcm_pm_ops, bcm_suspend, bcm_resume);
|
||||
|
||||
static struct platform_driver bcm_driver = {
|
||||
.probe = bcm_probe,
|
||||
.remove = bcm_remove,
|
||||
.driver = {
|
||||
.name = "hci_bcm",
|
||||
.acpi_match_table = ACPI_PTR(bcm_acpi_match),
|
||||
.pm = &bcm_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
int __init bcm_init(void)
|
||||
{
|
||||
platform_driver_register(&bcm_driver);
|
||||
|
||||
return hci_uart_register_proto(&bcm_proto);
|
||||
}
|
||||
|
||||
int __exit bcm_deinit(void)
|
||||
{
|
||||
platform_driver_unregister(&bcm_driver);
|
||||
|
||||
return hci_uart_unregister_proto(&bcm_proto);
|
||||
}
|
||||
|
||||
@@ -810,6 +810,9 @@ static int __init hci_uart_init(void)
|
||||
#ifdef CONFIG_BT_HCIUART_BCM
|
||||
bcm_init();
|
||||
#endif
|
||||
#ifdef CONFIG_BT_HCIUART_QCA
|
||||
qca_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -839,6 +842,9 @@ static void __exit hci_uart_exit(void)
|
||||
#ifdef CONFIG_BT_HCIUART_BCM
|
||||
bcm_deinit();
|
||||
#endif
|
||||
#ifdef CONFIG_BT_HCIUART_QCA
|
||||
qca_deinit();
|
||||
#endif
|
||||
|
||||
/* Release tty registration of line discipline */
|
||||
err = tty_unregister_ldisc(N_HCI);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@
|
||||
#define HCIUARTGETFLAGS _IOR('U', 204, int)
|
||||
|
||||
/* UART protocols */
|
||||
#define HCI_UART_MAX_PROTO 8
|
||||
#define HCI_UART_MAX_PROTO 9
|
||||
|
||||
#define HCI_UART_H4 0
|
||||
#define HCI_UART_BCSP 1
|
||||
@@ -45,6 +45,7 @@
|
||||
#define HCI_UART_ATH3K 5
|
||||
#define HCI_UART_INTEL 6
|
||||
#define HCI_UART_BCM 7
|
||||
#define HCI_UART_QCA 8
|
||||
|
||||
#define HCI_UART_RAW_DEVICE 0
|
||||
#define HCI_UART_RESET_ON_INIT 1
|
||||
@@ -176,3 +177,8 @@ int intel_deinit(void);
|
||||
int bcm_init(void);
|
||||
int bcm_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_QCA
|
||||
int qca_init(void);
|
||||
int qca_deinit(void);
|
||||
#endif
|
||||
|
||||
@@ -97,9 +97,7 @@ struct at86rf230_local {
|
||||
|
||||
struct at86rf230_state_change irq;
|
||||
|
||||
bool tx_aret;
|
||||
unsigned long cal_timeout;
|
||||
s8 max_frame_retries;
|
||||
bool is_tx;
|
||||
bool is_tx_from_off;
|
||||
u8 tx_retry;
|
||||
@@ -651,7 +649,7 @@ at86rf230_tx_complete(void *context)
|
||||
|
||||
enable_irq(ctx->irq);
|
||||
|
||||
ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret);
|
||||
ieee802154_xmit_complete(lp->hw, lp->tx_skb, false);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -760,17 +758,10 @@ at86rf230_irq_trx_end(struct at86rf230_local *lp)
|
||||
{
|
||||
if (lp->is_tx) {
|
||||
lp->is_tx = 0;
|
||||
|
||||
if (lp->tx_aret)
|
||||
at86rf230_async_state_change(lp, &lp->irq,
|
||||
STATE_FORCE_TX_ON,
|
||||
at86rf230_tx_trac_status,
|
||||
true);
|
||||
else
|
||||
at86rf230_async_state_change(lp, &lp->irq,
|
||||
STATE_RX_AACK_ON,
|
||||
at86rf230_tx_complete,
|
||||
true);
|
||||
at86rf230_async_state_change(lp, &lp->irq,
|
||||
STATE_FORCE_TX_ON,
|
||||
at86rf230_tx_trac_status,
|
||||
true);
|
||||
} else {
|
||||
at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
|
||||
at86rf230_rx_trac_check, true);
|
||||
@@ -876,24 +867,16 @@ at86rf230_xmit_start(void *context)
|
||||
struct at86rf230_state_change *ctx = context;
|
||||
struct at86rf230_local *lp = ctx->lp;
|
||||
|
||||
/* In ARET mode we need to go into STATE_TX_ARET_ON after we
|
||||
* are in STATE_TX_ON. The pfad differs here, so we change
|
||||
* the complete handler.
|
||||
*/
|
||||
if (lp->tx_aret) {
|
||||
if (lp->is_tx_from_off) {
|
||||
lp->is_tx_from_off = false;
|
||||
at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
|
||||
at86rf230_write_frame,
|
||||
false);
|
||||
} else {
|
||||
at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
|
||||
at86rf230_xmit_tx_on,
|
||||
false);
|
||||
}
|
||||
/* check if we change from off state */
|
||||
if (lp->is_tx_from_off) {
|
||||
lp->is_tx_from_off = false;
|
||||
at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
|
||||
at86rf230_write_frame,
|
||||
false);
|
||||
} else {
|
||||
at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
|
||||
at86rf230_write_frame, false);
|
||||
at86rf230_xmit_tx_on,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1267,15 +1250,8 @@ static int
|
||||
at86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
|
||||
{
|
||||
struct at86rf230_local *lp = hw->priv;
|
||||
int rc = 0;
|
||||
|
||||
lp->tx_aret = retries >= 0;
|
||||
lp->max_frame_retries = retries;
|
||||
|
||||
if (retries >= 0)
|
||||
rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
|
||||
|
||||
return rc;
|
||||
return at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -833,6 +833,7 @@ static int cc2520_get_platform_data(struct spi_device *spi,
|
||||
if (!spi_pdata)
|
||||
return -ENOENT;
|
||||
*pdata = *spi_pdata;
|
||||
priv->fifo_pin = pdata->fifo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +197,27 @@
|
||||
#define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
|
||||
#define LOWPAN_NHC_UDP_CS_C 0x04 /* checksum elided */
|
||||
|
||||
#define LOWPAN_PRIV_SIZE(llpriv_size) \
|
||||
(sizeof(struct lowpan_priv) + llpriv_size)
|
||||
|
||||
enum lowpan_lltypes {
|
||||
LOWPAN_LLTYPE_BTLE,
|
||||
LOWPAN_LLTYPE_IEEE802154,
|
||||
};
|
||||
|
||||
struct lowpan_priv {
|
||||
enum lowpan_lltypes lltype;
|
||||
|
||||
/* must be last */
|
||||
u8 priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
||||
static inline
|
||||
struct lowpan_priv *lowpan_priv(const struct net_device *dev)
|
||||
{
|
||||
return netdev_priv(dev);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* print data in line */
|
||||
static inline void raw_dump_inline(const char *caller, char *msg,
|
||||
@@ -372,6 +393,8 @@ lowpan_uncompress_size(const struct sk_buff *skb, u16 *dgram_offset)
|
||||
return skb->len + uncomp_header - ret;
|
||||
}
|
||||
|
||||
void lowpan_netdev_setup(struct net_device *dev, enum lowpan_lltypes lltype);
|
||||
|
||||
int
|
||||
lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
|
||||
const u8 *saddr, const u8 saddr_type,
|
||||
|
||||
@@ -512,9 +512,11 @@ struct hci_conn_params {
|
||||
HCI_AUTO_CONN_DIRECT,
|
||||
HCI_AUTO_CONN_ALWAYS,
|
||||
HCI_AUTO_CONN_LINK_LOSS,
|
||||
HCI_AUTO_CONN_EXPLICIT,
|
||||
} auto_connect;
|
||||
|
||||
struct hci_conn *conn;
|
||||
bool explicit_connect;
|
||||
};
|
||||
|
||||
extern struct list_head hci_dev_list;
|
||||
@@ -639,6 +641,7 @@ enum {
|
||||
HCI_CONN_DROP,
|
||||
HCI_CONN_PARAM_REMOVAL_PEND,
|
||||
HCI_CONN_NEW_LINK_KEY,
|
||||
HCI_CONN_SCANNING,
|
||||
};
|
||||
|
||||
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
||||
@@ -808,6 +811,26 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type == LE_LINK && c->state == BT_CONNECT &&
|
||||
!test_bit(HCI_CONN_SCANNING, &c->flags)) {
|
||||
rcu_read_unlock();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hci_disconnect(struct hci_conn *conn, __u8 reason);
|
||||
bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
|
||||
void hci_sco_setup(struct hci_conn *conn, __u8 status);
|
||||
@@ -823,6 +846,9 @@ void hci_chan_del(struct hci_chan *chan);
|
||||
void hci_chan_list_flush(struct hci_conn *conn);
|
||||
struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
|
||||
|
||||
struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level,
|
||||
u16 conn_timeout, u8 role);
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u16 conn_timeout,
|
||||
u8 role);
|
||||
@@ -988,6 +1014,9 @@ void hci_conn_params_clear_disabled(struct hci_dev *hdev);
|
||||
struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
|
||||
bdaddr_t *addr,
|
||||
u8 addr_type);
|
||||
struct hci_conn_params *hci_explicit_connect_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *addr,
|
||||
u8 addr_type);
|
||||
|
||||
void hci_uuids_clear(struct hci_dev *hdev);
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@ struct cfg802154_ops {
|
||||
s8 max_frame_retries);
|
||||
int (*set_lbt_mode)(struct wpan_phy *wpan_phy,
|
||||
struct wpan_dev *wpan_dev, bool mode);
|
||||
int (*set_ackreq_default)(struct wpan_phy *wpan_phy,
|
||||
struct wpan_dev *wpan_dev, bool ackreq);
|
||||
};
|
||||
|
||||
static inline bool
|
||||
@@ -173,6 +175,9 @@ struct wpan_dev {
|
||||
struct list_head list;
|
||||
struct net_device *netdev;
|
||||
|
||||
/* lowpan interface, set when the wpan_dev belongs to one lowpan_dev */
|
||||
struct net_device *lowpan_dev;
|
||||
|
||||
u32 identifier;
|
||||
|
||||
/* MAC PIB */
|
||||
@@ -193,6 +198,9 @@ struct wpan_dev {
|
||||
bool lbt;
|
||||
|
||||
bool promiscuous_mode;
|
||||
|
||||
/* fallback for acknowledgment bit setting */
|
||||
bool ackreq;
|
||||
};
|
||||
|
||||
#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev)
|
||||
|
||||
@@ -52,6 +52,8 @@ enum nl802154_commands {
|
||||
|
||||
NL802154_CMD_SET_LBT_MODE,
|
||||
|
||||
NL802154_CMD_SET_ACKREQ_DEFAULT,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL802154_CMD_MAX below */
|
||||
@@ -104,6 +106,8 @@ enum nl802154_attrs {
|
||||
|
||||
NL802154_ATTR_SUPPORTED_COMMANDS,
|
||||
|
||||
NL802154_ATTR_ACKREQ_DEFAULT,
|
||||
|
||||
/* add attributes here, update the policy in nl802154.c */
|
||||
|
||||
__NL802154_ATTR_AFTER_LAST,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
obj-$(CONFIG_6LOWPAN) += 6lowpan.o
|
||||
|
||||
6lowpan-y := iphc.o nhc.o
|
||||
6lowpan-y := core.o iphc.o nhc.o
|
||||
|
||||
#rfc6282 nhcs
|
||||
obj-$(CONFIG_6LOWPAN_NHC_DEST) += nhc_dest.o
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* 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.
|
||||
*
|
||||
* Authors:
|
||||
* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <net/6lowpan.h>
|
||||
|
||||
void lowpan_netdev_setup(struct net_device *dev, enum lowpan_lltypes lltype)
|
||||
{
|
||||
lowpan_priv(dev)->lltype = lltype;
|
||||
}
|
||||
EXPORT_SYMBOL(lowpan_netdev_setup);
|
||||
|
||||
static int __init lowpan_module_init(void)
|
||||
{
|
||||
request_module_nowait("ipv6");
|
||||
|
||||
request_module_nowait("nhc_dest");
|
||||
request_module_nowait("nhc_fragment");
|
||||
request_module_nowait("nhc_hop");
|
||||
request_module_nowait("nhc_ipv6");
|
||||
request_module_nowait("nhc_mobility");
|
||||
request_module_nowait("nhc_routing");
|
||||
request_module_nowait("nhc_udp");
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(lowpan_module_init);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user