Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93c284ee authored by Andrei Emeltchenko's avatar Andrei Emeltchenko Committed by Gustavo Padovan
Browse files

Bluetooth: AMP: Write remote AMP Assoc



When receiving HCI Command Status after HCI Create Physical Link
execute HCI Write Remote AMP Assoc command to AMP controller.

Signed-off-by: default avatarAndrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
parent a02226d6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -39,5 +39,7 @@ void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
			struct hci_conn *hcon);
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);

#endif /* __AMP_H */
+2 −0
Original line number Diff line number Diff line
@@ -127,6 +127,8 @@ struct le_scan_params {
struct amp_assoc {
	__u16	len;
	__u16	offset;
	__u16	rem_len;
	__u16	len_so_far;
	__u8	data[HCI_MAX_AMP_ASSOC_SIZE];
};

+80 −0
Original line number Diff line number Diff line
@@ -233,6 +233,86 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}


/* Write AMP Assoc data fragments, returns true with last fragment written*/
static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
				     struct hci_conn *hcon)
{
	struct hci_cp_write_remote_amp_assoc *cp;
	struct amp_mgr *mgr = hcon->amp_mgr;
	struct amp_ctrl *ctrl;
	u16 frag_len, len;

	ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
	if (!ctrl)
		return false;

	if (!ctrl->assoc_rem_len) {
		BT_DBG("all fragments are written");
		ctrl->assoc_rem_len = ctrl->assoc_len;
		ctrl->assoc_len_so_far = 0;

		amp_ctrl_put(ctrl);
		return true;
	}

	frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
	len = frag_len + sizeof(*cp);

	cp = kzalloc(len, GFP_KERNEL);
	if (!cp) {
		amp_ctrl_put(ctrl);
		return false;
	}

	BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u",
	       hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);

	cp->phy_handle = hcon->handle;
	cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
	cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
	memcpy(cp->frag, ctrl->assoc, frag_len);

	ctrl->assoc_len_so_far += frag_len;
	ctrl->assoc_rem_len -= frag_len;

	amp_ctrl_put(ctrl);

	hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);

	kfree(cp);

	return false;
}

void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
{
	struct hci_conn *hcon;

	BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);

	hcon = hci_conn_hash_lookup_handle(hdev, handle);
	if (!hcon)
		return;

	amp_write_rem_assoc_frag(hdev, hcon);
}

void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
{
	struct hci_conn *hcon;

	BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);

	hcon = hci_conn_hash_lookup_handle(hdev, handle);
	if (!hcon)
		return;

	BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon);

	amp_write_rem_assoc_frag(hdev, hcon);
}

void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
			struct hci_conn *hcon)
{
+29 −0
Original line number Diff line number Diff line
@@ -1215,6 +1215,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
	hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
}

static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
					  struct sk_buff *skb)
{
	struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;

	BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
	       hdev->name, rp->status, rp->phy_handle);

	if (rp->status)
		return;

	amp_write_rem_assoc_continue(hdev, rp->phy_handle);
}

static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
	BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -1700,7 +1714,18 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)

static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
{
	struct hci_cp_create_phy_link *cp;

	BT_DBG("%s status 0x%2.2x", hdev->name, status);

	if (status)
		return;

	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
	if (!cp)
		return;

	amp_write_remote_assoc(hdev, cp->phy_handle);
}

static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -2436,6 +2461,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
		hci_cc_write_le_host_supported(hdev, skb);
		break;

	case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
		hci_cc_write_remote_amp_assoc(hdev, skb);
		break;

	default:
		BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
		break;