mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-11 11:55:28 +02:00
Revert "Bluetooth: HCI: Remove HCI_AMP support"
This reverts commit5af2e235b0
which is commit84a4bb6548
upstream. It breaks the Android kernel abi and can be brought back in the future in an abi-safe way if it is really needed. Bug: 161946584 Change-Id: I46c1b881dedde98ee4820e04781cb399e3b5fc3d Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
parent
cfa231a1fa
commit
4091ea13a1
|
@ -121,6 +121,13 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
||||||
((event->data[2] == MODULE_BROUGHT_UP) ||
|
((event->data[2] == MODULE_BROUGHT_UP) ||
|
||||||
(event->data[2] == MODULE_ALREADY_UP)) ?
|
(event->data[2] == MODULE_ALREADY_UP)) ?
|
||||||
"Bring-up succeed" : "Bring-up failed");
|
"Bring-up succeed" : "Bring-up failed");
|
||||||
|
|
||||||
|
if (event->length > 3 && event->data[3])
|
||||||
|
priv->btmrvl_dev.dev_type = HCI_AMP;
|
||||||
|
else
|
||||||
|
priv->btmrvl_dev.dev_type = HCI_PRIMARY;
|
||||||
|
|
||||||
|
BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type);
|
||||||
} else if (priv->btmrvl_dev.sendcmdflag &&
|
} else if (priv->btmrvl_dev.sendcmdflag &&
|
||||||
event->data[1] == MODULE_SHUTDOWN_REQ) {
|
event->data[1] == MODULE_SHUTDOWN_REQ) {
|
||||||
BT_DBG("EVENT:%s", (event->data[2]) ?
|
BT_DBG("EVENT:%s", (event->data[2]) ?
|
||||||
|
@ -679,6 +686,8 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
|
||||||
hdev->wakeup = btmrvl_wakeup;
|
hdev->wakeup = btmrvl_wakeup;
|
||||||
SET_HCIDEV_DEV(hdev, &card->func->dev);
|
SET_HCIDEV_DEV(hdev, &card->func->dev);
|
||||||
|
|
||||||
|
hdev->dev_type = priv->btmrvl_dev.dev_type;
|
||||||
|
|
||||||
ret = hci_register_dev(hdev);
|
ret = hci_register_dev(hdev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
BT_ERR("Can not register HCI device");
|
BT_ERR("Can not register HCI device");
|
||||||
|
|
|
@ -134,6 +134,7 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
|
||||||
hdev->bus = HCI_USB;
|
hdev->bus = HCI_USB;
|
||||||
|
|
||||||
hci_set_drvdata(hdev, h_adapter);
|
hci_set_drvdata(hdev, h_adapter);
|
||||||
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
hdev->open = rsi_hci_open;
|
hdev->open = rsi_hci_open;
|
||||||
hdev->close = rsi_hci_close;
|
hdev->close = rsi_hci_close;
|
||||||
hdev->flush = rsi_hci_flush;
|
hdev->flush = rsi_hci_flush;
|
||||||
|
|
|
@ -32,6 +32,9 @@ static const struct sdio_device_id btsdio_table[] = {
|
||||||
/* Generic Bluetooth Type-B SDIO device */
|
/* Generic Bluetooth Type-B SDIO device */
|
||||||
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
|
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
|
||||||
|
|
||||||
|
/* Generic Bluetooth AMP controller */
|
||||||
|
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) },
|
||||||
|
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -316,6 +319,11 @@ static int btsdio_probe(struct sdio_func *func,
|
||||||
hdev->bus = HCI_SDIO;
|
hdev->bus = HCI_SDIO;
|
||||||
hci_set_drvdata(hdev, data);
|
hci_set_drvdata(hdev, data);
|
||||||
|
|
||||||
|
if (id->class == SDIO_CLASS_BT_AMP)
|
||||||
|
hdev->dev_type = HCI_AMP;
|
||||||
|
else
|
||||||
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
|
|
||||||
data->hdev = hdev;
|
data->hdev = hdev;
|
||||||
|
|
||||||
SET_HCIDEV_DEV(hdev, &func->dev);
|
SET_HCIDEV_DEV(hdev, &func->dev);
|
||||||
|
|
|
@ -4308,6 +4308,11 @@ static int btusb_probe(struct usb_interface *intf,
|
||||||
hdev->bus = HCI_USB;
|
hdev->bus = HCI_USB;
|
||||||
hci_set_drvdata(hdev, data);
|
hci_set_drvdata(hdev, data);
|
||||||
|
|
||||||
|
if (id->driver_info & BTUSB_AMP)
|
||||||
|
hdev->dev_type = HCI_AMP;
|
||||||
|
else
|
||||||
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
|
|
||||||
data->hdev = hdev;
|
data->hdev = hdev;
|
||||||
|
|
||||||
SET_HCIDEV_DEV(hdev, &intf->dev);
|
SET_HCIDEV_DEV(hdev, &intf->dev);
|
||||||
|
|
|
@ -2361,6 +2361,7 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
bcm4377->hdev = hdev;
|
bcm4377->hdev = hdev;
|
||||||
|
|
||||||
hdev->bus = HCI_PCI;
|
hdev->bus = HCI_PCI;
|
||||||
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
hdev->open = bcm4377_hci_open;
|
hdev->open = bcm4377_hci_open;
|
||||||
hdev->close = bcm4377_hci_close;
|
hdev->close = bcm4377_hci_close;
|
||||||
hdev->send = bcm4377_hci_send_frame;
|
hdev->send = bcm4377_hci_send_frame;
|
||||||
|
|
|
@ -667,6 +667,11 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
||||||
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
|
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
|
||||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||||
|
|
||||||
|
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
|
||||||
|
hdev->dev_type = HCI_AMP;
|
||||||
|
else
|
||||||
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
|
|
||||||
/* Only call open() for the protocol after hdev is fully initialized as
|
/* Only call open() for the protocol after hdev is fully initialized as
|
||||||
* open() (or a timer/workqueue it starts) may attempt to reference it.
|
* open() (or a timer/workqueue it starts) may attempt to reference it.
|
||||||
*/
|
*/
|
||||||
|
@ -717,6 +722,7 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
|
||||||
{
|
{
|
||||||
unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) |
|
unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) |
|
||||||
BIT(HCI_UART_RESET_ON_INIT) |
|
BIT(HCI_UART_RESET_ON_INIT) |
|
||||||
|
BIT(HCI_UART_CREATE_AMP) |
|
||||||
BIT(HCI_UART_INIT_PENDING) |
|
BIT(HCI_UART_INIT_PENDING) |
|
||||||
BIT(HCI_UART_EXT_CONFIG) |
|
BIT(HCI_UART_EXT_CONFIG) |
|
||||||
BIT(HCI_UART_VND_DETECT);
|
BIT(HCI_UART_VND_DETECT);
|
||||||
|
|
|
@ -366,6 +366,11 @@ int hci_uart_register_device_priv(struct hci_uart *hu,
|
||||||
if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
|
if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
|
||||||
set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
|
set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
|
||||||
|
|
||||||
|
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
|
||||||
|
hdev->dev_type = HCI_AMP;
|
||||||
|
else
|
||||||
|
hdev->dev_type = HCI_PRIMARY;
|
||||||
|
|
||||||
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
#define HCI_UART_RAW_DEVICE 0
|
#define HCI_UART_RAW_DEVICE 0
|
||||||
#define HCI_UART_RESET_ON_INIT 1
|
#define HCI_UART_RESET_ON_INIT 1
|
||||||
|
#define HCI_UART_CREATE_AMP 2
|
||||||
#define HCI_UART_INIT_PENDING 3
|
#define HCI_UART_INIT_PENDING 3
|
||||||
#define HCI_UART_EXT_CONFIG 4
|
#define HCI_UART_EXT_CONFIG 4
|
||||||
#define HCI_UART_VND_DETECT 5
|
#define HCI_UART_VND_DETECT 5
|
||||||
|
|
|
@ -384,10 +384,17 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
__u8 dev_type;
|
||||||
|
|
||||||
if (data->hdev)
|
if (data->hdev)
|
||||||
return -EBADFD;
|
return -EBADFD;
|
||||||
|
|
||||||
|
/* bits 0-1 are dev_type (Primary or AMP) */
|
||||||
|
dev_type = opcode & 0x03;
|
||||||
|
|
||||||
|
if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* bits 2-5 are reserved (must be zero) */
|
/* bits 2-5 are reserved (must be zero) */
|
||||||
if (opcode & 0x3c)
|
if (opcode & 0x3c)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -405,6 +412,7 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||||
data->hdev = hdev;
|
data->hdev = hdev;
|
||||||
|
|
||||||
hdev->bus = HCI_VIRTUAL;
|
hdev->bus = HCI_VIRTUAL;
|
||||||
|
hdev->dev_type = dev_type;
|
||||||
hci_set_drvdata(hdev, data);
|
hci_set_drvdata(hdev, data);
|
||||||
|
|
||||||
hdev->open = vhci_open_dev;
|
hdev->open = vhci_open_dev;
|
||||||
|
@ -626,7 +634,7 @@ static void vhci_open_timeout(struct work_struct *work)
|
||||||
struct vhci_data *data = container_of(work, struct vhci_data,
|
struct vhci_data *data = container_of(work, struct vhci_data,
|
||||||
open_timeout.work);
|
open_timeout.work);
|
||||||
|
|
||||||
vhci_create_device(data, 0x00);
|
vhci_create_device(data, amp ? HCI_AMP : HCI_PRIMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vhci_open(struct inode *inode, struct file *file)
|
static int vhci_open(struct inode *inode, struct file *file)
|
||||||
|
|
|
@ -274,6 +274,7 @@ static int virtbt_probe(struct virtio_device *vdev)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VIRTIO_BT_CONFIG_TYPE_PRIMARY:
|
case VIRTIO_BT_CONFIG_TYPE_PRIMARY:
|
||||||
|
case VIRTIO_BT_CONFIG_TYPE_AMP:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -302,6 +303,7 @@ static int virtbt_probe(struct virtio_device *vdev)
|
||||||
vbt->hdev = hdev;
|
vbt->hdev = hdev;
|
||||||
|
|
||||||
hdev->bus = HCI_VIRTIO;
|
hdev->bus = HCI_VIRTIO;
|
||||||
|
hdev->dev_type = type;
|
||||||
hci_set_drvdata(hdev, vbt);
|
hci_set_drvdata(hdev, vbt);
|
||||||
|
|
||||||
hdev->open = virtbt_open;
|
hdev->open = virtbt_open;
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
|
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
|
||||||
|
|
||||||
#define HCI_LINK_KEY_SIZE 16
|
#define HCI_LINK_KEY_SIZE 16
|
||||||
|
#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
|
||||||
|
|
||||||
|
#define HCI_MAX_AMP_ASSOC_SIZE 672
|
||||||
|
|
||||||
#define HCI_MAX_CPB_DATA_SIZE 252
|
#define HCI_MAX_CPB_DATA_SIZE 252
|
||||||
|
|
||||||
|
@ -68,6 +71,26 @@
|
||||||
#define HCI_SMD 9
|
#define HCI_SMD 9
|
||||||
#define HCI_VIRTIO 10
|
#define HCI_VIRTIO 10
|
||||||
|
|
||||||
|
/* HCI controller types */
|
||||||
|
#define HCI_PRIMARY 0x00
|
||||||
|
#define HCI_AMP 0x01
|
||||||
|
|
||||||
|
/* First BR/EDR Controller shall have ID = 0 */
|
||||||
|
#define AMP_ID_BREDR 0x00
|
||||||
|
|
||||||
|
/* AMP controller types */
|
||||||
|
#define AMP_TYPE_BREDR 0x00
|
||||||
|
#define AMP_TYPE_80211 0x01
|
||||||
|
|
||||||
|
/* AMP controller status */
|
||||||
|
#define AMP_STATUS_POWERED_DOWN 0x00
|
||||||
|
#define AMP_STATUS_BLUETOOTH_ONLY 0x01
|
||||||
|
#define AMP_STATUS_NO_CAPACITY 0x02
|
||||||
|
#define AMP_STATUS_LOW_CAPACITY 0x03
|
||||||
|
#define AMP_STATUS_MEDIUM_CAPACITY 0x04
|
||||||
|
#define AMP_STATUS_HIGH_CAPACITY 0x05
|
||||||
|
#define AMP_STATUS_FULL_CAPACITY 0x06
|
||||||
|
|
||||||
/* HCI device quirks */
|
/* HCI device quirks */
|
||||||
enum {
|
enum {
|
||||||
/* When this quirk is set, the HCI Reset command is send when
|
/* When this quirk is set, the HCI Reset command is send when
|
||||||
|
@ -503,6 +526,7 @@ enum {
|
||||||
#define ESCO_LINK 0x02
|
#define ESCO_LINK 0x02
|
||||||
/* Low Energy links do not have defined link type. Use invented one */
|
/* Low Energy links do not have defined link type. Use invented one */
|
||||||
#define LE_LINK 0x80
|
#define LE_LINK 0x80
|
||||||
|
#define AMP_LINK 0x81
|
||||||
#define ISO_LINK 0x82
|
#define ISO_LINK 0x82
|
||||||
#define INVALID_LINK 0xff
|
#define INVALID_LINK 0xff
|
||||||
|
|
||||||
|
@ -916,6 +940,56 @@ struct hci_cp_io_capability_neg_reply {
|
||||||
__u8 reason;
|
__u8 reason;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_CREATE_PHY_LINK 0x0435
|
||||||
|
struct hci_cp_create_phy_link {
|
||||||
|
__u8 phy_handle;
|
||||||
|
__u8 key_len;
|
||||||
|
__u8 key_type;
|
||||||
|
__u8 key[HCI_AMP_LINK_KEY_SIZE];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_ACCEPT_PHY_LINK 0x0436
|
||||||
|
struct hci_cp_accept_phy_link {
|
||||||
|
__u8 phy_handle;
|
||||||
|
__u8 key_len;
|
||||||
|
__u8 key_type;
|
||||||
|
__u8 key[HCI_AMP_LINK_KEY_SIZE];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_DISCONN_PHY_LINK 0x0437
|
||||||
|
struct hci_cp_disconn_phy_link {
|
||||||
|
__u8 phy_handle;
|
||||||
|
__u8 reason;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ext_flow_spec {
|
||||||
|
__u8 id;
|
||||||
|
__u8 stype;
|
||||||
|
__le16 msdu;
|
||||||
|
__le32 sdu_itime;
|
||||||
|
__le32 acc_lat;
|
||||||
|
__le32 flush_to;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_CREATE_LOGICAL_LINK 0x0438
|
||||||
|
#define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439
|
||||||
|
struct hci_cp_create_accept_logical_link {
|
||||||
|
__u8 phy_handle;
|
||||||
|
struct ext_flow_spec tx_flow_spec;
|
||||||
|
struct ext_flow_spec rx_flow_spec;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_DISCONN_LOGICAL_LINK 0x043a
|
||||||
|
struct hci_cp_disconn_logical_link {
|
||||||
|
__le16 log_handle;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_LOGICAL_LINK_CANCEL 0x043b
|
||||||
|
struct hci_cp_logical_link_cancel {
|
||||||
|
__u8 phy_handle;
|
||||||
|
__u8 flow_spec_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
|
#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
|
||||||
struct hci_coding_format {
|
struct hci_coding_format {
|
||||||
__u8 id;
|
__u8 id;
|
||||||
|
@ -1537,6 +1611,46 @@ struct hci_rp_read_enc_key_size {
|
||||||
__u8 key_size;
|
__u8 key_size;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409
|
||||||
|
struct hci_rp_read_local_amp_info {
|
||||||
|
__u8 status;
|
||||||
|
__u8 amp_status;
|
||||||
|
__le32 total_bw;
|
||||||
|
__le32 max_bw;
|
||||||
|
__le32 min_latency;
|
||||||
|
__le32 max_pdu;
|
||||||
|
__u8 amp_type;
|
||||||
|
__le16 pal_cap;
|
||||||
|
__le16 max_assoc_size;
|
||||||
|
__le32 max_flush_to;
|
||||||
|
__le32 be_flush_to;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_READ_LOCAL_AMP_ASSOC 0x140a
|
||||||
|
struct hci_cp_read_local_amp_assoc {
|
||||||
|
__u8 phy_handle;
|
||||||
|
__le16 len_so_far;
|
||||||
|
__le16 max_len;
|
||||||
|
} __packed;
|
||||||
|
struct hci_rp_read_local_amp_assoc {
|
||||||
|
__u8 status;
|
||||||
|
__u8 phy_handle;
|
||||||
|
__le16 rem_len;
|
||||||
|
__u8 frag[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b
|
||||||
|
struct hci_cp_write_remote_amp_assoc {
|
||||||
|
__u8 phy_handle;
|
||||||
|
__le16 len_so_far;
|
||||||
|
__le16 rem_len;
|
||||||
|
__u8 frag[];
|
||||||
|
} __packed;
|
||||||
|
struct hci_rp_write_remote_amp_assoc {
|
||||||
|
__u8 status;
|
||||||
|
__u8 phy_handle;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define HCI_OP_GET_MWS_TRANSPORT_CONFIG 0x140c
|
#define HCI_OP_GET_MWS_TRANSPORT_CONFIG 0x140c
|
||||||
|
|
||||||
#define HCI_OP_ENABLE_DUT_MODE 0x1803
|
#define HCI_OP_ENABLE_DUT_MODE 0x1803
|
||||||
|
|
|
@ -127,6 +127,7 @@ enum suspended_state {
|
||||||
struct hci_conn_hash {
|
struct hci_conn_hash {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
unsigned int acl_num;
|
unsigned int acl_num;
|
||||||
|
unsigned int amp_num;
|
||||||
unsigned int sco_num;
|
unsigned int sco_num;
|
||||||
unsigned int iso_num;
|
unsigned int iso_num;
|
||||||
unsigned int le_num;
|
unsigned int le_num;
|
||||||
|
@ -341,6 +342,14 @@ struct adv_monitor {
|
||||||
/* Default authenticated payload timeout 30s */
|
/* Default authenticated payload timeout 30s */
|
||||||
#define DEFAULT_AUTH_PAYLOAD_TIMEOUT 0x0bb8
|
#define DEFAULT_AUTH_PAYLOAD_TIMEOUT 0x0bb8
|
||||||
|
|
||||||
|
struct amp_assoc {
|
||||||
|
__u16 len;
|
||||||
|
__u16 offset;
|
||||||
|
__u16 rem_len;
|
||||||
|
__u16 len_so_far;
|
||||||
|
__u8 data[HCI_MAX_AMP_ASSOC_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
#define HCI_MAX_PAGES 3
|
#define HCI_MAX_PAGES 3
|
||||||
|
|
||||||
struct hci_dev {
|
struct hci_dev {
|
||||||
|
@ -353,6 +362,7 @@ struct hci_dev {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
__u16 id;
|
__u16 id;
|
||||||
__u8 bus;
|
__u8 bus;
|
||||||
|
__u8 dev_type;
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
bdaddr_t setup_addr;
|
bdaddr_t setup_addr;
|
||||||
bdaddr_t public_addr;
|
bdaddr_t public_addr;
|
||||||
|
@ -458,6 +468,21 @@ struct hci_dev {
|
||||||
__u16 sniff_min_interval;
|
__u16 sniff_min_interval;
|
||||||
__u16 sniff_max_interval;
|
__u16 sniff_max_interval;
|
||||||
|
|
||||||
|
__u8 amp_status;
|
||||||
|
__u32 amp_total_bw;
|
||||||
|
__u32 amp_max_bw;
|
||||||
|
__u32 amp_min_latency;
|
||||||
|
__u32 amp_max_pdu;
|
||||||
|
__u8 amp_type;
|
||||||
|
__u16 amp_pal_cap;
|
||||||
|
__u16 amp_assoc_size;
|
||||||
|
__u32 amp_max_flush_to;
|
||||||
|
__u32 amp_be_flush_to;
|
||||||
|
|
||||||
|
struct amp_assoc loc_assoc;
|
||||||
|
|
||||||
|
__u8 flow_ctl_mode;
|
||||||
|
|
||||||
unsigned int auto_accept_delay;
|
unsigned int auto_accept_delay;
|
||||||
|
|
||||||
unsigned long quirks;
|
unsigned long quirks;
|
||||||
|
@ -477,6 +502,11 @@ struct hci_dev {
|
||||||
unsigned int le_pkts;
|
unsigned int le_pkts;
|
||||||
unsigned int iso_pkts;
|
unsigned int iso_pkts;
|
||||||
|
|
||||||
|
__u16 block_len;
|
||||||
|
__u16 block_mtu;
|
||||||
|
__u16 num_blocks;
|
||||||
|
__u16 block_cnt;
|
||||||
|
|
||||||
unsigned long acl_last_tx;
|
unsigned long acl_last_tx;
|
||||||
unsigned long sco_last_tx;
|
unsigned long sco_last_tx;
|
||||||
unsigned long le_last_tx;
|
unsigned long le_last_tx;
|
||||||
|
@ -752,6 +782,7 @@ struct hci_conn {
|
||||||
void *l2cap_data;
|
void *l2cap_data;
|
||||||
void *sco_data;
|
void *sco_data;
|
||||||
void *iso_data;
|
void *iso_data;
|
||||||
|
struct amp_mgr *amp_mgr;
|
||||||
|
|
||||||
struct list_head link_list;
|
struct list_head link_list;
|
||||||
struct hci_conn *parent;
|
struct hci_conn *parent;
|
||||||
|
@ -783,7 +814,6 @@ struct hci_chan {
|
||||||
struct sk_buff_head data_q;
|
struct sk_buff_head data_q;
|
||||||
unsigned int sent;
|
unsigned int sent;
|
||||||
__u8 state;
|
__u8 state;
|
||||||
bool amp;
|
|
||||||
|
|
||||||
ANDROID_KABI_RESERVE(1);
|
ANDROID_KABI_RESERVE(1);
|
||||||
};
|
};
|
||||||
|
@ -996,6 +1026,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
|
||||||
case ACL_LINK:
|
case ACL_LINK:
|
||||||
h->acl_num++;
|
h->acl_num++;
|
||||||
break;
|
break;
|
||||||
|
case AMP_LINK:
|
||||||
|
h->amp_num++;
|
||||||
|
break;
|
||||||
case LE_LINK:
|
case LE_LINK:
|
||||||
h->le_num++;
|
h->le_num++;
|
||||||
if (c->role == HCI_ROLE_SLAVE)
|
if (c->role == HCI_ROLE_SLAVE)
|
||||||
|
@ -1022,6 +1055,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
|
||||||
case ACL_LINK:
|
case ACL_LINK:
|
||||||
h->acl_num--;
|
h->acl_num--;
|
||||||
break;
|
break;
|
||||||
|
case AMP_LINK:
|
||||||
|
h->amp_num--;
|
||||||
|
break;
|
||||||
case LE_LINK:
|
case LE_LINK:
|
||||||
h->le_num--;
|
h->le_num--;
|
||||||
if (c->role == HCI_ROLE_SLAVE)
|
if (c->role == HCI_ROLE_SLAVE)
|
||||||
|
@ -1043,6 +1079,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ACL_LINK:
|
case ACL_LINK:
|
||||||
return h->acl_num;
|
return h->acl_num;
|
||||||
|
case AMP_LINK:
|
||||||
|
return h->amp_num;
|
||||||
case LE_LINK:
|
case LE_LINK:
|
||||||
return h->le_num;
|
return h->le_num;
|
||||||
case SCO_LINK:
|
case SCO_LINK:
|
||||||
|
@ -1059,7 +1097,7 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct hci_conn_hash *c = &hdev->conn_hash;
|
struct hci_conn_hash *c = &hdev->conn_hash;
|
||||||
|
|
||||||
return c->acl_num + c->sco_num + c->le_num + c->iso_num;
|
return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
|
static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
|
||||||
|
@ -1545,6 +1583,10 @@ static inline void hci_conn_drop(struct hci_conn *conn)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AMP_LINK:
|
||||||
|
timeo = conn->disc_timeout;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
timeo = 0;
|
timeo = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
enum virtio_bt_config_type {
|
enum virtio_bt_config_type {
|
||||||
VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0,
|
VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0,
|
||||||
|
VIRTIO_BT_CONFIG_TYPE_AMP = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum virtio_bt_config_vendor {
|
enum virtio_bt_config_vendor {
|
||||||
|
|
|
@ -1200,7 +1200,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
|
||||||
|
|
||||||
list_for_each_entry(d, &hci_dev_list, list) {
|
list_for_each_entry(d, &hci_dev_list, list) {
|
||||||
if (!test_bit(HCI_UP, &d->flags) ||
|
if (!test_bit(HCI_UP, &d->flags) ||
|
||||||
hci_dev_test_flag(d, HCI_USER_CHANNEL))
|
hci_dev_test_flag(d, HCI_USER_CHANNEL) ||
|
||||||
|
d->dev_type != HCI_PRIMARY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Simple routing:
|
/* Simple routing:
|
||||||
|
|
|
@ -395,6 +395,11 @@ int hci_inquiry(void __user *arg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdev->dev_type != HCI_PRIMARY) {
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
|
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -747,6 +752,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdev->dev_type != HCI_PRIMARY) {
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
|
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -900,7 +910,7 @@ int hci_get_dev_info(void __user *arg)
|
||||||
|
|
||||||
strscpy(di.name, hdev->name, sizeof(di.name));
|
strscpy(di.name, hdev->name, sizeof(di.name));
|
||||||
di.bdaddr = hdev->bdaddr;
|
di.bdaddr = hdev->bdaddr;
|
||||||
di.type = (hdev->bus & 0x0f);
|
di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4);
|
||||||
di.flags = flags;
|
di.flags = flags;
|
||||||
di.pkt_type = hdev->pkt_type;
|
di.pkt_type = hdev->pkt_type;
|
||||||
if (lmp_bredr_capable(hdev)) {
|
if (lmp_bredr_capable(hdev)) {
|
||||||
|
@ -985,7 +995,8 @@ static void hci_power_on(struct work_struct *work)
|
||||||
*/
|
*/
|
||||||
if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
|
if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
|
||||||
hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
|
hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
|
||||||
(!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
|
(hdev->dev_type == HCI_PRIMARY &&
|
||||||
|
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
|
||||||
!bacmp(&hdev->static_addr, BDADDR_ANY))) {
|
!bacmp(&hdev->static_addr, BDADDR_ANY))) {
|
||||||
hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
|
hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
|
||||||
hci_dev_do_close(hdev);
|
hci_dev_do_close(hdev);
|
||||||
|
@ -2593,7 +2604,21 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||||
if (!hdev->open || !hdev->close || !hdev->send)
|
if (!hdev->open || !hdev->close || !hdev->send)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Do not allow HCI_AMP devices to register at index 0,
|
||||||
|
* so the index can be used as the AMP controller ID.
|
||||||
|
*/
|
||||||
|
switch (hdev->dev_type) {
|
||||||
|
case HCI_PRIMARY:
|
||||||
id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);
|
id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);
|
||||||
|
break;
|
||||||
|
case HCI_AMP:
|
||||||
|
id = ida_alloc_range(&hci_index_ida, 1, HCI_MAX_ID - 1,
|
||||||
|
GFP_KERNEL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
|
@ -2645,10 +2670,12 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||||
hci_dev_set_flag(hdev, HCI_SETUP);
|
hci_dev_set_flag(hdev, HCI_SETUP);
|
||||||
hci_dev_set_flag(hdev, HCI_AUTO_OFF);
|
hci_dev_set_flag(hdev, HCI_AUTO_OFF);
|
||||||
|
|
||||||
|
if (hdev->dev_type == HCI_PRIMARY) {
|
||||||
/* Assume BR/EDR support until proven otherwise (such as
|
/* Assume BR/EDR support until proven otherwise (such as
|
||||||
* through reading supported features during init.
|
* through reading supported features during init.
|
||||||
*/
|
*/
|
||||||
hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
|
hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
write_lock(&hci_dev_list_lock);
|
write_lock(&hci_dev_list_lock);
|
||||||
list_add(&hdev->list, &hci_dev_list);
|
list_add(&hdev->list, &hci_dev_list);
|
||||||
|
@ -3184,7 +3211,17 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
|
||||||
|
|
||||||
hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
|
hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
|
||||||
|
|
||||||
|
switch (hdev->dev_type) {
|
||||||
|
case HCI_PRIMARY:
|
||||||
hci_add_acl_hdr(skb, conn->handle, flags);
|
hci_add_acl_hdr(skb, conn->handle, flags);
|
||||||
|
break;
|
||||||
|
case HCI_AMP:
|
||||||
|
hci_add_acl_hdr(skb, chan->handle, flags);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
list = skb_shinfo(skb)->frag_list;
|
list = skb_shinfo(skb)->frag_list;
|
||||||
if (!list) {
|
if (!list) {
|
||||||
|
@ -3344,6 +3381,9 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote)
|
||||||
case ACL_LINK:
|
case ACL_LINK:
|
||||||
cnt = hdev->acl_cnt;
|
cnt = hdev->acl_cnt;
|
||||||
break;
|
break;
|
||||||
|
case AMP_LINK:
|
||||||
|
cnt = hdev->block_cnt;
|
||||||
|
break;
|
||||||
case SCO_LINK:
|
case SCO_LINK:
|
||||||
case ESCO_LINK:
|
case ESCO_LINK:
|
||||||
cnt = hdev->sco_cnt;
|
cnt = hdev->sco_cnt;
|
||||||
|
@ -3541,6 +3581,12 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
/* Calculate count of blocks used by this packet */
|
||||||
|
return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
|
||||||
|
}
|
||||||
|
|
||||||
static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
|
static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
|
||||||
{
|
{
|
||||||
unsigned long last_tx;
|
unsigned long last_tx;
|
||||||
|
@ -3654,15 +3700,81 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
|
||||||
hci_prio_recalculate(hdev, ACL_LINK);
|
hci_prio_recalculate(hdev, ACL_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_sched_acl_blk(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
unsigned int cnt = hdev->block_cnt;
|
||||||
|
struct hci_chan *chan;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int quote;
|
||||||
|
u8 type;
|
||||||
|
|
||||||
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
|
if (hdev->dev_type == HCI_AMP)
|
||||||
|
type = AMP_LINK;
|
||||||
|
else
|
||||||
|
type = ACL_LINK;
|
||||||
|
|
||||||
|
__check_timeout(hdev, cnt, type);
|
||||||
|
|
||||||
|
while (hdev->block_cnt > 0 &&
|
||||||
|
(chan = hci_chan_sent(hdev, type, "e))) {
|
||||||
|
u32 priority = (skb_peek(&chan->data_q))->priority;
|
||||||
|
while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
|
||||||
|
int blocks;
|
||||||
|
|
||||||
|
BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
|
||||||
|
skb->len, skb->priority);
|
||||||
|
|
||||||
|
/* Stop if priority has changed */
|
||||||
|
if (skb->priority < priority)
|
||||||
|
break;
|
||||||
|
|
||||||
|
skb = skb_dequeue(&chan->data_q);
|
||||||
|
|
||||||
|
blocks = __get_blocks(hdev, skb);
|
||||||
|
if (blocks > hdev->block_cnt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hci_conn_enter_active_mode(chan->conn,
|
||||||
|
bt_cb(skb)->force_active);
|
||||||
|
|
||||||
|
hci_send_frame(hdev, skb);
|
||||||
|
hdev->acl_last_tx = jiffies;
|
||||||
|
|
||||||
|
hdev->block_cnt -= blocks;
|
||||||
|
quote -= blocks;
|
||||||
|
|
||||||
|
chan->sent += blocks;
|
||||||
|
chan->conn->sent += blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt != hdev->block_cnt)
|
||||||
|
hci_prio_recalculate(hdev, type);
|
||||||
|
}
|
||||||
|
|
||||||
static void hci_sched_acl(struct hci_dev *hdev)
|
static void hci_sched_acl(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
/* No ACL link over BR/EDR controller */
|
/* No ACL link over BR/EDR controller */
|
||||||
if (!hci_conn_num(hdev, ACL_LINK))
|
if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_PRIMARY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* No AMP link over AMP controller */
|
||||||
|
if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (hdev->flow_ctl_mode) {
|
||||||
|
case HCI_FLOW_CTL_MODE_PACKET_BASED:
|
||||||
hci_sched_acl_pkt(hdev);
|
hci_sched_acl_pkt(hdev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCI_FLOW_CTL_MODE_BLOCK_BASED:
|
||||||
|
hci_sched_acl_blk(hdev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_sched_le(struct hci_dev *hdev)
|
static void hci_sched_le(struct hci_dev *hdev)
|
||||||
|
|
|
@ -917,6 +917,21 @@ static u8 hci_cc_read_local_ext_features(struct hci_dev *hdev, void *data,
|
||||||
return rp->status;
|
return rp->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 hci_cc_read_flow_control_mode(struct hci_dev *hdev, void *data,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_rp_read_flow_control_mode *rp = data;
|
||||||
|
|
||||||
|
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
|
||||||
|
|
||||||
|
if (rp->status)
|
||||||
|
return rp->status;
|
||||||
|
|
||||||
|
hdev->flow_ctl_mode = rp->mode;
|
||||||
|
|
||||||
|
return rp->status;
|
||||||
|
}
|
||||||
|
|
||||||
static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data,
|
static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -1060,6 +1075,28 @@ static u8 hci_cc_write_page_scan_type(struct hci_dev *hdev, void *data,
|
||||||
return rp->status;
|
return rp->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 hci_cc_read_data_block_size(struct hci_dev *hdev, void *data,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_rp_read_data_block_size *rp = data;
|
||||||
|
|
||||||
|
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
|
||||||
|
|
||||||
|
if (rp->status)
|
||||||
|
return rp->status;
|
||||||
|
|
||||||
|
hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
|
||||||
|
hdev->block_len = __le16_to_cpu(rp->block_len);
|
||||||
|
hdev->num_blocks = __le16_to_cpu(rp->num_blocks);
|
||||||
|
|
||||||
|
hdev->block_cnt = hdev->num_blocks;
|
||||||
|
|
||||||
|
BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
|
||||||
|
hdev->block_cnt, hdev->block_len);
|
||||||
|
|
||||||
|
return rp->status;
|
||||||
|
}
|
||||||
|
|
||||||
static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data,
|
static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -1094,6 +1131,30 @@ unlock:
|
||||||
return rp->status;
|
return rp->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 hci_cc_read_local_amp_info(struct hci_dev *hdev, void *data,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_rp_read_local_amp_info *rp = data;
|
||||||
|
|
||||||
|
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
|
||||||
|
|
||||||
|
if (rp->status)
|
||||||
|
return rp->status;
|
||||||
|
|
||||||
|
hdev->amp_status = rp->amp_status;
|
||||||
|
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
|
||||||
|
hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
|
||||||
|
hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
|
||||||
|
hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
|
||||||
|
hdev->amp_type = rp->amp_type;
|
||||||
|
hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
|
||||||
|
hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
|
||||||
|
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
|
||||||
|
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
|
||||||
|
|
||||||
|
return rp->status;
|
||||||
|
}
|
||||||
|
|
||||||
static u8 hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, void *data,
|
static u8 hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, void *data,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -4073,6 +4134,12 @@ static const struct hci_cc {
|
||||||
HCI_CC(HCI_OP_READ_PAGE_SCAN_TYPE, hci_cc_read_page_scan_type,
|
HCI_CC(HCI_OP_READ_PAGE_SCAN_TYPE, hci_cc_read_page_scan_type,
|
||||||
sizeof(struct hci_rp_read_page_scan_type)),
|
sizeof(struct hci_rp_read_page_scan_type)),
|
||||||
HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_TYPE, hci_cc_write_page_scan_type),
|
HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_TYPE, hci_cc_write_page_scan_type),
|
||||||
|
HCI_CC(HCI_OP_READ_DATA_BLOCK_SIZE, hci_cc_read_data_block_size,
|
||||||
|
sizeof(struct hci_rp_read_data_block_size)),
|
||||||
|
HCI_CC(HCI_OP_READ_FLOW_CONTROL_MODE, hci_cc_read_flow_control_mode,
|
||||||
|
sizeof(struct hci_rp_read_flow_control_mode)),
|
||||||
|
HCI_CC(HCI_OP_READ_LOCAL_AMP_INFO, hci_cc_read_local_amp_info,
|
||||||
|
sizeof(struct hci_rp_read_local_amp_info)),
|
||||||
HCI_CC(HCI_OP_READ_CLOCK, hci_cc_read_clock,
|
HCI_CC(HCI_OP_READ_CLOCK, hci_cc_read_clock,
|
||||||
sizeof(struct hci_rp_read_clock)),
|
sizeof(struct hci_rp_read_clock)),
|
||||||
HCI_CC(HCI_OP_READ_ENC_KEY_SIZE, hci_cc_read_enc_key_size,
|
HCI_CC(HCI_OP_READ_ENC_KEY_SIZE, hci_cc_read_enc_key_size,
|
||||||
|
@ -4407,6 +4474,11 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
|
||||||
flex_array_size(ev, handles, ev->num)))
|
flex_array_size(ev, handles, ev->num)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
|
||||||
|
bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bt_dev_dbg(hdev, "num %d", ev->num);
|
bt_dev_dbg(hdev, "num %d", ev->num);
|
||||||
|
|
||||||
for (i = 0; i < ev->num; i++) {
|
for (i = 0; i < ev->num; i++) {
|
||||||
|
@ -4474,6 +4546,78 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
|
||||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev,
|
||||||
|
__u16 handle)
|
||||||
|
{
|
||||||
|
struct hci_chan *chan;
|
||||||
|
|
||||||
|
switch (hdev->dev_type) {
|
||||||
|
case HCI_PRIMARY:
|
||||||
|
return hci_conn_hash_lookup_handle(hdev, handle);
|
||||||
|
case HCI_AMP:
|
||||||
|
chan = hci_chan_lookup_handle(hdev, handle);
|
||||||
|
if (chan)
|
||||||
|
return chan->conn;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hci_num_comp_blocks_evt(struct hci_dev *hdev, void *data,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_ev_num_comp_blocks *ev = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_BLOCKS,
|
||||||
|
flex_array_size(ev, handles, ev->num_hndl)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
|
||||||
|
bt_dev_err(hdev, "wrong event for mode %d",
|
||||||
|
hdev->flow_ctl_mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_dev_dbg(hdev, "num_blocks %d num_hndl %d", ev->num_blocks,
|
||||||
|
ev->num_hndl);
|
||||||
|
|
||||||
|
for (i = 0; i < ev->num_hndl; i++) {
|
||||||
|
struct hci_comp_blocks_info *info = &ev->handles[i];
|
||||||
|
struct hci_conn *conn = NULL;
|
||||||
|
__u16 handle, block_count;
|
||||||
|
|
||||||
|
handle = __le16_to_cpu(info->handle);
|
||||||
|
block_count = __le16_to_cpu(info->blocks);
|
||||||
|
|
||||||
|
conn = __hci_conn_lookup_handle(hdev, handle);
|
||||||
|
if (!conn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
conn->sent -= block_count;
|
||||||
|
|
||||||
|
switch (conn->type) {
|
||||||
|
case ACL_LINK:
|
||||||
|
case AMP_LINK:
|
||||||
|
hdev->block_cnt += block_count;
|
||||||
|
if (hdev->block_cnt > hdev->num_blocks)
|
||||||
|
hdev->block_cnt = hdev->num_blocks;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
bt_dev_err(hdev, "unknown type %d conn %p",
|
||||||
|
conn->type, conn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||||
|
}
|
||||||
|
|
||||||
static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
|
static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -7387,6 +7531,9 @@ static const struct hci_ev {
|
||||||
/* [0x3e = HCI_EV_LE_META] */
|
/* [0x3e = HCI_EV_LE_META] */
|
||||||
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
|
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
|
||||||
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
|
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
|
||||||
|
/* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */
|
||||||
|
HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt,
|
||||||
|
sizeof(struct hci_ev_num_comp_blocks)),
|
||||||
/* [0xff = HCI_EV_VENDOR] */
|
/* [0xff = HCI_EV_VENDOR] */
|
||||||
HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
|
HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
|
||||||
};
|
};
|
||||||
|
|
|
@ -485,7 +485,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ni = skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
|
ni = skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
|
||||||
ni->type = 0x00; /* Old hdev->dev_type */
|
ni->type = hdev->dev_type;
|
||||||
ni->bus = hdev->bus;
|
ni->bus = hdev->bus;
|
||||||
bacpy(&ni->bdaddr, &hdev->bdaddr);
|
bacpy(&ni->bdaddr, &hdev->bdaddr);
|
||||||
memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name,
|
memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name,
|
||||||
|
@ -1007,6 +1007,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
|
||||||
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
|
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (hdev->dev_type != HCI_PRIMARY)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case HCISETRAW:
|
case HCISETRAW:
|
||||||
if (!capable(CAP_NET_ADMIN))
|
if (!capable(CAP_NET_ADMIN))
|
||||||
|
|
|
@ -3440,6 +3440,10 @@ static int hci_unconf_init_sync(struct hci_dev *hdev)
|
||||||
/* Read Local Supported Features. */
|
/* Read Local Supported Features. */
|
||||||
static int hci_read_local_features_sync(struct hci_dev *hdev)
|
static int hci_read_local_features_sync(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
/* Not all AMP controllers support this command */
|
||||||
|
if (hdev->dev_type == HCI_AMP && !(hdev->commands[14] & 0x20))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_FEATURES,
|
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_FEATURES,
|
||||||
0, NULL, HCI_CMD_TIMEOUT);
|
0, NULL, HCI_CMD_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
@ -3474,6 +3478,51 @@ static int hci_read_local_cmds_sync(struct hci_dev *hdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read Local AMP Info */
|
||||||
|
static int hci_read_local_amp_info_sync(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_AMP_INFO,
|
||||||
|
0, NULL, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read Data Blk size */
|
||||||
|
static int hci_read_data_block_size_sync(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_READ_DATA_BLOCK_SIZE,
|
||||||
|
0, NULL, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read Flow Control Mode */
|
||||||
|
static int hci_read_flow_control_mode_sync(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_READ_FLOW_CONTROL_MODE,
|
||||||
|
0, NULL, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read Location Data */
|
||||||
|
static int hci_read_location_data_sync(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCATION_DATA,
|
||||||
|
0, NULL, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AMP Controller init stage 1 command sequence */
|
||||||
|
static const struct hci_init_stage amp_init1[] = {
|
||||||
|
/* HCI_OP_READ_LOCAL_VERSION */
|
||||||
|
HCI_INIT(hci_read_local_version_sync),
|
||||||
|
/* HCI_OP_READ_LOCAL_COMMANDS */
|
||||||
|
HCI_INIT(hci_read_local_cmds_sync),
|
||||||
|
/* HCI_OP_READ_LOCAL_AMP_INFO */
|
||||||
|
HCI_INIT(hci_read_local_amp_info_sync),
|
||||||
|
/* HCI_OP_READ_DATA_BLOCK_SIZE */
|
||||||
|
HCI_INIT(hci_read_data_block_size_sync),
|
||||||
|
/* HCI_OP_READ_FLOW_CONTROL_MODE */
|
||||||
|
HCI_INIT(hci_read_flow_control_mode_sync),
|
||||||
|
/* HCI_OP_READ_LOCATION_DATA */
|
||||||
|
HCI_INIT(hci_read_location_data_sync),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
static int hci_init1_sync(struct hci_dev *hdev)
|
static int hci_init1_sync(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -3487,9 +3536,28 @@ static int hci_init1_sync(struct hci_dev *hdev)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (hdev->dev_type) {
|
||||||
|
case HCI_PRIMARY:
|
||||||
|
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
|
||||||
return hci_init_stage_sync(hdev, br_init1);
|
return hci_init_stage_sync(hdev, br_init1);
|
||||||
|
case HCI_AMP:
|
||||||
|
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
|
||||||
|
return hci_init_stage_sync(hdev, amp_init1);
|
||||||
|
default:
|
||||||
|
bt_dev_err(hdev, "Unknown device type %d", hdev->dev_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AMP Controller init stage 2 command sequence */
|
||||||
|
static const struct hci_init_stage amp_init2[] = {
|
||||||
|
/* HCI_OP_READ_LOCAL_FEATURES */
|
||||||
|
HCI_INIT(hci_read_local_features_sync),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||||
static int hci_read_buffer_size_sync(struct hci_dev *hdev)
|
static int hci_read_buffer_size_sync(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
@ -3747,6 +3815,9 @@ static int hci_init2_sync(struct hci_dev *hdev)
|
||||||
|
|
||||||
bt_dev_dbg(hdev, "");
|
bt_dev_dbg(hdev, "");
|
||||||
|
|
||||||
|
if (hdev->dev_type == HCI_AMP)
|
||||||
|
return hci_init_stage_sync(hdev, amp_init2);
|
||||||
|
|
||||||
err = hci_init_stage_sync(hdev, hci_init2);
|
err = hci_init_stage_sync(hdev, hci_init2);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -4584,6 +4655,13 @@ static int hci_init_sync(struct hci_dev *hdev)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* HCI_PRIMARY covers both single-mode LE, BR/EDR and dual-mode
|
||||||
|
* BR/EDR/LE type controllers. AMP controllers only need the
|
||||||
|
* first two stages of init.
|
||||||
|
*/
|
||||||
|
if (hdev->dev_type != HCI_PRIMARY)
|
||||||
|
return 0;
|
||||||
|
|
||||||
err = hci_init3_sync(hdev);
|
err = hci_init3_sync(hdev);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -4812,8 +4890,12 @@ int hci_dev_open_sync(struct hci_dev *hdev)
|
||||||
* In case of user channel usage, it is not important
|
* In case of user channel usage, it is not important
|
||||||
* if a public address or static random address is
|
* if a public address or static random address is
|
||||||
* available.
|
* available.
|
||||||
|
*
|
||||||
|
* This check is only valid for BR/EDR controllers
|
||||||
|
* since AMP controllers do not have an address.
|
||||||
*/
|
*/
|
||||||
if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
||||||
|
hdev->dev_type == HCI_PRIMARY &&
|
||||||
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
|
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
|
||||||
!bacmp(&hdev->static_addr, BDADDR_ANY)) {
|
!bacmp(&hdev->static_addr, BDADDR_ANY)) {
|
||||||
ret = -EADDRNOTAVAIL;
|
ret = -EADDRNOTAVAIL;
|
||||||
|
@ -4848,7 +4930,8 @@ int hci_dev_open_sync(struct hci_dev *hdev)
|
||||||
!hci_dev_test_flag(hdev, HCI_CONFIG) &&
|
!hci_dev_test_flag(hdev, HCI_CONFIG) &&
|
||||||
!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
|
!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
|
||||||
!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
||||||
hci_dev_test_flag(hdev, HCI_MGMT)) {
|
hci_dev_test_flag(hdev, HCI_MGMT) &&
|
||||||
|
hdev->dev_type == HCI_PRIMARY) {
|
||||||
ret = hci_powered_update_sync(hdev);
|
ret = hci_powered_update_sync(hdev);
|
||||||
mgmt_power_on(hdev, ret);
|
mgmt_power_on(hdev, ret);
|
||||||
}
|
}
|
||||||
|
@ -4994,7 +5077,8 @@ int hci_dev_close_sync(struct hci_dev *hdev)
|
||||||
|
|
||||||
auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
|
auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
|
||||||
|
|
||||||
if (!auto_off && !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
if (!auto_off && hdev->dev_type == HCI_PRIMARY &&
|
||||||
|
!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
|
||||||
hci_dev_test_flag(hdev, HCI_MGMT))
|
hci_dev_test_flag(hdev, HCI_MGMT))
|
||||||
__mgmt_power_off(hdev);
|
__mgmt_power_off(hdev);
|
||||||
|
|
||||||
|
@ -5056,6 +5140,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
|
||||||
hdev->flags &= BIT(HCI_RAW);
|
hdev->flags &= BIT(HCI_RAW);
|
||||||
hci_dev_clear_volatile_flags(hdev);
|
hci_dev_clear_volatile_flags(hdev);
|
||||||
|
|
||||||
|
/* Controller radio is available but is currently powered down */
|
||||||
|
hdev->amp_status = AMP_STATUS_POWERED_DOWN;
|
||||||
|
|
||||||
memset(hdev->eir, 0, sizeof(hdev->eir));
|
memset(hdev->eir, 0, sizeof(hdev->eir));
|
||||||
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
|
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
|
||||||
bacpy(&hdev->random_addr, BDADDR_ANY);
|
bacpy(&hdev->random_addr, BDADDR_ANY);
|
||||||
|
@ -5092,7 +5179,8 @@ static int hci_power_on_sync(struct hci_dev *hdev)
|
||||||
*/
|
*/
|
||||||
if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
|
if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
|
||||||
hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
|
hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
|
||||||
(!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
|
(hdev->dev_type == HCI_PRIMARY &&
|
||||||
|
!bacmp(&hdev->bdaddr, BDADDR_ANY) &&
|
||||||
!bacmp(&hdev->static_addr, BDADDR_ANY))) {
|
!bacmp(&hdev->static_addr, BDADDR_ANY))) {
|
||||||
hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
|
hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
|
||||||
hci_dev_close_sync(hdev);
|
hci_dev_close_sync(hdev);
|
||||||
|
@ -5195,11 +5283,27 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hci_disconnect_phy_link_sync(struct hci_dev *hdev, u16 handle,
|
||||||
|
u8 reason)
|
||||||
|
{
|
||||||
|
struct hci_cp_disconn_phy_link cp;
|
||||||
|
|
||||||
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
cp.phy_handle = HCI_PHY_HANDLE(handle);
|
||||||
|
cp.reason = reason;
|
||||||
|
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_DISCONN_PHY_LINK,
|
||||||
|
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||||
u8 reason)
|
u8 reason)
|
||||||
{
|
{
|
||||||
struct hci_cp_disconnect cp;
|
struct hci_cp_disconnect cp;
|
||||||
|
|
||||||
|
if (conn->type == AMP_LINK)
|
||||||
|
return hci_disconnect_phy_link_sync(hdev, conn->handle, reason);
|
||||||
|
|
||||||
if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) {
|
if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) {
|
||||||
/* This is a BIS connection, hci_conn_del will
|
/* This is a BIS connection, hci_conn_del will
|
||||||
* do the necessary cleanup.
|
* do the necessary cleanup.
|
||||||
|
|
|
@ -3930,7 +3930,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
|
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
|
||||||
u8 *data, u8 rsp_code)
|
u8 *data, u8 rsp_code, u8 amp_id)
|
||||||
{
|
{
|
||||||
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
|
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
|
||||||
struct l2cap_conn_rsp rsp;
|
struct l2cap_conn_rsp rsp;
|
||||||
|
@ -4008,9 +4008,18 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
|
||||||
result = L2CAP_CR_PEND;
|
result = L2CAP_CR_PEND;
|
||||||
status = L2CAP_CS_AUTHOR_PEND;
|
status = L2CAP_CS_AUTHOR_PEND;
|
||||||
chan->ops->defer(chan);
|
chan->ops->defer(chan);
|
||||||
|
} else {
|
||||||
|
/* Force pending result for AMP controllers.
|
||||||
|
* The connection will succeed after the
|
||||||
|
* physical link is up.
|
||||||
|
*/
|
||||||
|
if (amp_id == AMP_ID_BREDR) {
|
||||||
|
l2cap_state_change(chan, BT_CONFIG);
|
||||||
|
result = L2CAP_CR_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
l2cap_state_change(chan, BT_CONNECT2);
|
l2cap_state_change(chan, BT_CONNECT2);
|
||||||
result = L2CAP_CR_PEND;
|
result = L2CAP_CR_PEND;
|
||||||
|
}
|
||||||
status = L2CAP_CS_NO_INFO;
|
status = L2CAP_CS_NO_INFO;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -4075,7 +4084,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
|
||||||
mgmt_device_connected(hdev, hcon, NULL, 0);
|
mgmt_device_connected(hdev, hcon, NULL, 0);
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP);
|
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7488,6 +7497,10 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
/* For AMP controller do not create l2cap conn */
|
||||||
|
if (!conn && hcon->hdev->dev_type != HCI_PRIMARY)
|
||||||
|
goto drop;
|
||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
conn = l2cap_conn_add(hcon);
|
conn = l2cap_conn_add(hcon);
|
||||||
|
|
||||||
|
|
|
@ -443,7 +443,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
list_for_each_entry(d, &hci_dev_list, list) {
|
list_for_each_entry(d, &hci_dev_list, list) {
|
||||||
if (!hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
if (d->dev_type == HCI_PRIMARY &&
|
||||||
|
!hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +468,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
|
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
|
if (d->dev_type == HCI_PRIMARY &&
|
||||||
|
!hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
|
||||||
rp->index[count++] = cpu_to_le16(d->id);
|
rp->index[count++] = cpu_to_le16(d->id);
|
||||||
bt_dev_dbg(hdev, "Added hci%u", d->id);
|
bt_dev_dbg(hdev, "Added hci%u", d->id);
|
||||||
}
|
}
|
||||||
|
@ -501,7 +503,8 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
list_for_each_entry(d, &hci_dev_list, list) {
|
list_for_each_entry(d, &hci_dev_list, list) {
|
||||||
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
if (d->dev_type == HCI_PRIMARY &&
|
||||||
|
hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +528,8 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
|
||||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
|
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
|
if (d->dev_type == HCI_PRIMARY &&
|
||||||
|
hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
|
||||||
rp->index[count++] = cpu_to_le16(d->id);
|
rp->index[count++] = cpu_to_le16(d->id);
|
||||||
bt_dev_dbg(hdev, "Added hci%u", d->id);
|
bt_dev_dbg(hdev, "Added hci%u", d->id);
|
||||||
}
|
}
|
||||||
|
@ -557,8 +561,10 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
|
||||||
read_lock(&hci_dev_list_lock);
|
read_lock(&hci_dev_list_lock);
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
list_for_each_entry(d, &hci_dev_list, list)
|
list_for_each_entry(d, &hci_dev_list, list) {
|
||||||
|
if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
|
||||||
count++;
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
|
rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC);
|
||||||
if (!rp) {
|
if (!rp) {
|
||||||
|
@ -579,10 +585,16 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
|
||||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
|
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (d->dev_type == HCI_PRIMARY) {
|
||||||
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
||||||
rp->entry[count].type = 0x01;
|
rp->entry[count].type = 0x01;
|
||||||
else
|
else
|
||||||
rp->entry[count].type = 0x00;
|
rp->entry[count].type = 0x00;
|
||||||
|
} else if (d->dev_type == HCI_AMP) {
|
||||||
|
rp->entry[count].type = 0x02;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
rp->entry[count].bus = d->bus;
|
rp->entry[count].bus = d->bus;
|
||||||
rp->entry[count++].index = cpu_to_le16(d->id);
|
rp->entry[count++].index = cpu_to_le16(d->id);
|
||||||
|
@ -9312,15 +9324,24 @@ void mgmt_index_added(struct hci_dev *hdev)
|
||||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
switch (hdev->dev_type) {
|
||||||
|
case HCI_PRIMARY:
|
||||||
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
|
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
|
||||||
mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0,
|
mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
|
||||||
HCI_MGMT_UNCONF_INDEX_EVENTS);
|
NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
|
||||||
ev.type = 0x01;
|
ev.type = 0x01;
|
||||||
} else {
|
} else {
|
||||||
mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
|
mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
|
||||||
HCI_MGMT_INDEX_EVENTS);
|
HCI_MGMT_INDEX_EVENTS);
|
||||||
ev.type = 0x00;
|
ev.type = 0x00;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case HCI_AMP:
|
||||||
|
ev.type = 0x02;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ev.bus = hdev->bus;
|
ev.bus = hdev->bus;
|
||||||
|
|
||||||
|
@ -9336,17 +9357,26 @@ void mgmt_index_removed(struct hci_dev *hdev)
|
||||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
switch (hdev->dev_type) {
|
||||||
|
case HCI_PRIMARY:
|
||||||
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
|
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
|
||||||
|
|
||||||
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
|
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
|
||||||
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
|
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
|
||||||
HCI_MGMT_UNCONF_INDEX_EVENTS);
|
NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
|
||||||
ev.type = 0x01;
|
ev.type = 0x01;
|
||||||
} else {
|
} else {
|
||||||
mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
|
mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
|
||||||
HCI_MGMT_INDEX_EVENTS);
|
HCI_MGMT_INDEX_EVENTS);
|
||||||
ev.type = 0x00;
|
ev.type = 0x00;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case HCI_AMP:
|
||||||
|
ev.type = 0x02;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ev.bus = hdev->bus;
|
ev.bus = hdev->bus;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user