Re: [PATCH 2/2] Bluetooth: Add __hci_cmd_sync() helper function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Johan,

> This patch adds a helper function for sending a single HCI command
> waiting for its completion and then returning back the parameters in the
> resulting command complete event (if there was one).
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@xxxxxxxxx>
> ---
> include/net/bluetooth/hci_core.h |    3 ++
> net/bluetooth/hci_core.c         |   93 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 96 insertions(+)
> 
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 0a1cb19..064b057 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -1057,6 +1057,9 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
> void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param);
> void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
> 
> +struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
> +			       void *param, u32 timeout);
> +
> int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
> void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
> void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 7008b4d..689c959 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -79,6 +79,99 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
> 	}
> }
> 
> +struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode)
> +{
> +	struct hci_ev_cmd_complete *ev;
> +	struct hci_event_hdr *hdr;
> +	struct sk_buff *skb;
> +
> +	hci_dev_lock(hdev);
> +
> +	if (hdev->recv_evt)
> +		skb = skb_clone(hdev->recv_evt, GFP_KERNEL);

why are we cloning this again. Can we not just return recv_evt and set it to NULL afterwards.

> +	else
> +		skb = NULL;
> +
> +	hci_dev_unlock(hdev);
> +
> +	if (!skb)
> +		return ERR_PTR(-ENODATA);
> +
> +	hdr = (void *) skb->data;
> +	skb_pull(skb, HCI_EVENT_HDR_SIZE);
> +
> +	if (hdr->evt != HCI_EV_CMD_COMPLETE) {
> +		BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
> +		goto failed;
> +	}
> +
> +	ev = (void *) skb->data;
> +	skb_pull(skb, sizeof(*ev));

Don't you think we should add some sanity length checks here.

> +
> +	if (opcode == __le16_to_cpu(ev->opcode))
> +		return skb;
> +
> +	BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode,
> +	       __le16_to_cpu(ev->opcode));
> +
> +failed:
> +	kfree_skb(skb);
> +	return ERR_PTR(-ENODATA);
> +}
> +
> +struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
> +			       void *param, u32 timeout)
> +{
> +	DECLARE_WAITQUEUE(wait, current);
> +	struct hci_request req;
> +	int err = 0;
> +
> +	BT_DBG("%s", hdev->name);
> +
> +	hci_req_init(&req, hdev);
> +
> +	hci_req_add(&req, opcode, plen, param);
> +
> +	hdev->req_status = HCI_REQ_PEND;
> +
> +	err = hci_req_run(&req, hci_req_sync_complete);
> +	if (err < 0)
> +		return ERR_PTR(err);
> +
> +	add_wait_queue(&hdev->req_wait_q, &wait);
> +	set_current_state(TASK_INTERRUPTIBLE);
> +
> +	schedule_timeout(timeout);
> +
> +	remove_wait_queue(&hdev->req_wait_q, &wait);
> +
> +	if (signal_pending(current))
> +		return ERR_PTR(-EINTR);
> +
> +	switch (hdev->req_status) {
> +	case HCI_REQ_DONE:
> +		err = -bt_to_errno(hdev->req_result);
> +		break;
> +
> +	case HCI_REQ_CANCELED:
> +		err = -hdev->req_result;
> +		break;
> +
> +	default:
> +		err = -ETIMEDOUT;
> +		break;
> +	}
> +
> +	hdev->req_status = hdev->req_result = 0;
> +
> +	BT_DBG("%s end: err %d", hdev->name, err);
> +
> +	if (err < 0)
> +		return ERR_PTR(err);
> +
> +	return hci_get_cmd_complete(hdev, opcode);
> +}
> +
> /* Execute request and wait for completion. */
> static int __hci_req_sync(struct hci_dev *hdev,
> 			  void (*func)(struct hci_request *req,

Regards

Marcel

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux