Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2018-10-20 Here's one more bluetooth-next pull request for the 4.20 kernel. - Added new USB ID for QCA_ROME controller - Added debug trace support from QCA wcn3990 controllers - Updated L2CAP to conform to latest Errata Service Release - Fix binding to non-removable BCM43430 devices 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:
Коммит
342149c557
|
@ -293,13 +293,17 @@ static int btsdio_probe(struct sdio_func *func,
|
||||||
tuple = tuple->next;
|
tuple = tuple->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BCM43341 devices soldered onto the PCB (non-removable) use an
|
/* Broadcom devices soldered onto the PCB (non-removable) use an
|
||||||
* uart connection for bluetooth, ignore the BT SDIO interface.
|
* UART connection for Bluetooth, ignore the BT SDIO interface.
|
||||||
*/
|
*/
|
||||||
if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
|
if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
|
||||||
func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
|
!mmc_card_is_removable(func->card->host)) {
|
||||||
!mmc_card_is_removable(func->card->host))
|
switch (func->device) {
|
||||||
return -ENODEV;
|
case SDIO_DEVICE_ID_BROADCOM_43341:
|
||||||
|
case SDIO_DEVICE_ID_BROADCOM_43430:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
|
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
|
|
@ -264,6 +264,7 @@ static const struct usb_device_id blacklist_table[] = {
|
||||||
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
||||||
|
|
||||||
/* QCA ROME chipset */
|
/* QCA ROME chipset */
|
||||||
|
{ USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME },
|
||||||
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
|
||||||
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
|
||||||
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME },
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/serdev.h>
|
#include <linux/serdev.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
|
@ -63,6 +64,9 @@
|
||||||
/* susclk rate */
|
/* susclk rate */
|
||||||
#define SUSCLK_RATE_32KHZ 32768
|
#define SUSCLK_RATE_32KHZ 32768
|
||||||
|
|
||||||
|
/* Controller debug log header */
|
||||||
|
#define QCA_DEBUG_HANDLE 0x2EDC
|
||||||
|
|
||||||
/* HCI_IBS transmit side sleep protocol states */
|
/* HCI_IBS transmit side sleep protocol states */
|
||||||
enum tx_ibs_states {
|
enum tx_ibs_states {
|
||||||
HCI_IBS_TX_ASLEEP,
|
HCI_IBS_TX_ASLEEP,
|
||||||
|
@ -849,6 +853,19 @@ static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
/* We receive debug logs from chip as an ACL packets.
|
||||||
|
* Instead of sending the data to ACL to decode the
|
||||||
|
* received data, we are pushing them to the above layers
|
||||||
|
* as a diagnostic packet.
|
||||||
|
*/
|
||||||
|
if (get_unaligned_le16(skb->data) == QCA_DEBUG_HANDLE)
|
||||||
|
return hci_recv_diag(hdev, skb);
|
||||||
|
|
||||||
|
return hci_recv_frame(hdev, skb);
|
||||||
|
}
|
||||||
|
|
||||||
#define QCA_IBS_SLEEP_IND_EVENT \
|
#define QCA_IBS_SLEEP_IND_EVENT \
|
||||||
.type = HCI_IBS_SLEEP_IND, \
|
.type = HCI_IBS_SLEEP_IND, \
|
||||||
.hlen = 0, \
|
.hlen = 0, \
|
||||||
|
@ -871,7 +888,7 @@ static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
.maxlen = HCI_MAX_IBS_SIZE
|
.maxlen = HCI_MAX_IBS_SIZE
|
||||||
|
|
||||||
static const struct h4_recv_pkt qca_recv_pkts[] = {
|
static const struct h4_recv_pkt qca_recv_pkts[] = {
|
||||||
{ H4_RECV_ACL, .recv = hci_recv_frame },
|
{ H4_RECV_ACL, .recv = qca_recv_acl_data },
|
||||||
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
||||||
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
||||||
{ QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind },
|
{ QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind },
|
||||||
|
|
|
@ -277,12 +277,19 @@ struct l2cap_conn_rsp {
|
||||||
#define L2CAP_CR_SEC_BLOCK 0x0003
|
#define L2CAP_CR_SEC_BLOCK 0x0003
|
||||||
#define L2CAP_CR_NO_MEM 0x0004
|
#define L2CAP_CR_NO_MEM 0x0004
|
||||||
#define L2CAP_CR_BAD_AMP 0x0005
|
#define L2CAP_CR_BAD_AMP 0x0005
|
||||||
#define L2CAP_CR_AUTHENTICATION 0x0005
|
#define L2CAP_CR_INVALID_SCID 0x0006
|
||||||
#define L2CAP_CR_AUTHORIZATION 0x0006
|
#define L2CAP_CR_SCID_IN_USE 0x0007
|
||||||
#define L2CAP_CR_BAD_KEY_SIZE 0x0007
|
|
||||||
#define L2CAP_CR_ENCRYPTION 0x0008
|
/* credit based connect results */
|
||||||
#define L2CAP_CR_INVALID_SCID 0x0009
|
#define L2CAP_CR_LE_SUCCESS 0x0000
|
||||||
#define L2CAP_CR_SCID_IN_USE 0x000A
|
#define L2CAP_CR_LE_BAD_PSM 0x0002
|
||||||
|
#define L2CAP_CR_LE_NO_MEM 0x0004
|
||||||
|
#define L2CAP_CR_LE_AUTHENTICATION 0x0005
|
||||||
|
#define L2CAP_CR_LE_AUTHORIZATION 0x0006
|
||||||
|
#define L2CAP_CR_LE_BAD_KEY_SIZE 0x0007
|
||||||
|
#define L2CAP_CR_LE_ENCRYPTION 0x0008
|
||||||
|
#define L2CAP_CR_LE_INVALID_SCID 0x0009
|
||||||
|
#define L2CAP_CR_LE_SCID_IN_USE 0X000A
|
||||||
|
|
||||||
/* connect/create channel status */
|
/* connect/create channel status */
|
||||||
#define L2CAP_CS_NO_INFO 0x0000
|
#define L2CAP_CS_NO_INFO 0x0000
|
||||||
|
|
|
@ -4937,31 +4937,27 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||||
hci_debugfs_create_conn(conn);
|
hci_debugfs_create_conn(conn);
|
||||||
hci_conn_add_sysfs(conn);
|
hci_conn_add_sysfs(conn);
|
||||||
|
|
||||||
if (!status) {
|
/* The remote features procedure is defined for master
|
||||||
/* The remote features procedure is defined for master
|
* role only. So only in case of an initiated connection
|
||||||
* role only. So only in case of an initiated connection
|
* request the remote features.
|
||||||
* request the remote features.
|
*
|
||||||
*
|
* If the local controller supports slave-initiated features
|
||||||
* If the local controller supports slave-initiated features
|
* exchange, then requesting the remote features in slave
|
||||||
* exchange, then requesting the remote features in slave
|
* role is possible. Otherwise just transition into the
|
||||||
* role is possible. Otherwise just transition into the
|
* connected state without requesting the remote features.
|
||||||
* connected state without requesting the remote features.
|
*/
|
||||||
*/
|
if (conn->out ||
|
||||||
if (conn->out ||
|
(hdev->le_features[0] & HCI_LE_SLAVE_FEATURES)) {
|
||||||
(hdev->le_features[0] & HCI_LE_SLAVE_FEATURES)) {
|
struct hci_cp_le_read_remote_features cp;
|
||||||
struct hci_cp_le_read_remote_features cp;
|
|
||||||
|
|
||||||
cp.handle = __cpu_to_le16(conn->handle);
|
cp.handle = __cpu_to_le16(conn->handle);
|
||||||
|
|
||||||
hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
|
hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
|
||||||
sizeof(cp), &cp);
|
sizeof(cp), &cp);
|
||||||
|
|
||||||
hci_conn_hold(conn);
|
hci_conn_hold(conn);
|
||||||
} else {
|
|
||||||
conn->state = BT_CONNECTED;
|
|
||||||
hci_connect_cfm(conn, status);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
conn->state = BT_CONNECTED;
|
||||||
hci_connect_cfm(conn, status);
|
hci_connect_cfm(conn, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -680,9 +680,9 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
|
||||||
u16 result;
|
u16 result;
|
||||||
|
|
||||||
if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
|
if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
|
||||||
result = L2CAP_CR_AUTHORIZATION;
|
result = L2CAP_CR_LE_AUTHORIZATION;
|
||||||
else
|
else
|
||||||
result = L2CAP_CR_BAD_PSM;
|
result = L2CAP_CR_LE_BAD_PSM;
|
||||||
|
|
||||||
l2cap_state_change(chan, BT_DISCONN);
|
l2cap_state_change(chan, BT_DISCONN);
|
||||||
|
|
||||||
|
@ -3670,7 +3670,7 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
|
||||||
rsp.mtu = cpu_to_le16(chan->imtu);
|
rsp.mtu = cpu_to_le16(chan->imtu);
|
||||||
rsp.mps = cpu_to_le16(chan->mps);
|
rsp.mps = cpu_to_le16(chan->mps);
|
||||||
rsp.credits = cpu_to_le16(chan->rx_credits);
|
rsp.credits = cpu_to_le16(chan->rx_credits);
|
||||||
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
|
rsp.result = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
|
||||||
|
|
||||||
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
|
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
|
||||||
&rsp);
|
&rsp);
|
||||||
|
@ -3816,9 +3816,17 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
|
||||||
|
|
||||||
result = L2CAP_CR_NO_MEM;
|
result = L2CAP_CR_NO_MEM;
|
||||||
|
|
||||||
/* Check if we already have channel with that dcid */
|
/* Check for valid dynamic CID range (as per Erratum 3253) */
|
||||||
if (__l2cap_get_chan_by_dcid(conn, scid))
|
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_DYN_END) {
|
||||||
|
result = L2CAP_CR_INVALID_SCID;
|
||||||
goto response;
|
goto response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we already have channel with that dcid */
|
||||||
|
if (__l2cap_get_chan_by_dcid(conn, scid)) {
|
||||||
|
result = L2CAP_CR_SCID_IN_USE;
|
||||||
|
goto response;
|
||||||
|
}
|
||||||
|
|
||||||
chan = pchan->ops->new_connection(pchan);
|
chan = pchan->ops->new_connection(pchan);
|
||||||
if (!chan)
|
if (!chan)
|
||||||
|
@ -5280,7 +5288,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
|
||||||
credits = __le16_to_cpu(rsp->credits);
|
credits = __le16_to_cpu(rsp->credits);
|
||||||
result = __le16_to_cpu(rsp->result);
|
result = __le16_to_cpu(rsp->result);
|
||||||
|
|
||||||
if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23 ||
|
if (result == L2CAP_CR_LE_SUCCESS && (mtu < 23 || mps < 23 ||
|
||||||
dcid < L2CAP_CID_DYN_START ||
|
dcid < L2CAP_CID_DYN_START ||
|
||||||
dcid > L2CAP_CID_LE_DYN_END))
|
dcid > L2CAP_CID_LE_DYN_END))
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
@ -5301,7 +5309,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
|
||||||
l2cap_chan_lock(chan);
|
l2cap_chan_lock(chan);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case L2CAP_CR_SUCCESS:
|
case L2CAP_CR_LE_SUCCESS:
|
||||||
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
|
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
|
||||||
err = -EBADSLT;
|
err = -EBADSLT;
|
||||||
break;
|
break;
|
||||||
|
@ -5315,8 +5323,8 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
|
||||||
l2cap_chan_ready(chan);
|
l2cap_chan_ready(chan);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L2CAP_CR_AUTHENTICATION:
|
case L2CAP_CR_LE_AUTHENTICATION:
|
||||||
case L2CAP_CR_ENCRYPTION:
|
case L2CAP_CR_LE_ENCRYPTION:
|
||||||
/* If we already have MITM protection we can't do
|
/* If we already have MITM protection we can't do
|
||||||
* anything.
|
* anything.
|
||||||
*/
|
*/
|
||||||
|
@ -5459,7 +5467,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
||||||
pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
|
pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
|
||||||
&conn->hcon->dst, LE_LINK);
|
&conn->hcon->dst, LE_LINK);
|
||||||
if (!pchan) {
|
if (!pchan) {
|
||||||
result = L2CAP_CR_BAD_PSM;
|
result = L2CAP_CR_LE_BAD_PSM;
|
||||||
chan = NULL;
|
chan = NULL;
|
||||||
goto response;
|
goto response;
|
||||||
}
|
}
|
||||||
|
@ -5469,28 +5477,28 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
||||||
|
|
||||||
if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
|
if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
|
||||||
SMP_ALLOW_STK)) {
|
SMP_ALLOW_STK)) {
|
||||||
result = L2CAP_CR_AUTHENTICATION;
|
result = L2CAP_CR_LE_AUTHENTICATION;
|
||||||
chan = NULL;
|
chan = NULL;
|
||||||
goto response_unlock;
|
goto response_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for valid dynamic CID range */
|
/* Check for valid dynamic CID range */
|
||||||
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
|
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
|
||||||
result = L2CAP_CR_INVALID_SCID;
|
result = L2CAP_CR_LE_INVALID_SCID;
|
||||||
chan = NULL;
|
chan = NULL;
|
||||||
goto response_unlock;
|
goto response_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we already have channel with that dcid */
|
/* Check if we already have channel with that dcid */
|
||||||
if (__l2cap_get_chan_by_dcid(conn, scid)) {
|
if (__l2cap_get_chan_by_dcid(conn, scid)) {
|
||||||
result = L2CAP_CR_SCID_IN_USE;
|
result = L2CAP_CR_LE_SCID_IN_USE;
|
||||||
chan = NULL;
|
chan = NULL;
|
||||||
goto response_unlock;
|
goto response_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan = pchan->ops->new_connection(pchan);
|
chan = pchan->ops->new_connection(pchan);
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
result = L2CAP_CR_NO_MEM;
|
result = L2CAP_CR_LE_NO_MEM;
|
||||||
goto response_unlock;
|
goto response_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5526,7 +5534,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
||||||
chan->ops->defer(chan);
|
chan->ops->defer(chan);
|
||||||
} else {
|
} else {
|
||||||
l2cap_chan_ready(chan);
|
l2cap_chan_ready(chan);
|
||||||
result = L2CAP_CR_SUCCESS;
|
result = L2CAP_CR_LE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
response_unlock:
|
response_unlock:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче