Bluetooth: Add support for custom event terminated commands
authorJohan Hedberg <johan.hedberg@intel.com>
Wed, 3 Apr 2013 18:50:29 +0000 (21:50 +0300)
committerJohan Hedberg <johan.hedberg@intel.com>
Thu, 4 Apr 2013 16:16:08 +0000 (19:16 +0300)
This patch adds support for having commands within HCI requests that do
not result in a command complete but some other event. This is at least
needed for some vendor specific commands to be issued in the
hdev->setup() procecure, but might also be useful for other commands.

The way that the support is implemented is by extending the skb control
buffer to have a field to indicate that the command is expected to
terminate with a special event. After sending the command each received
event can then be compared against this field through hdev->sent_cmd.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c

index ed6e9552252e56cba3e4ef7896c91863e900717a..591fee7d00604baa4f9d628833f5f60b1ac38ebc 100644 (file)
@@ -266,6 +266,7 @@ typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status);
 
 struct hci_req_ctrl {
        bool                    start;
+       u8                      event;
        hci_req_complete_t      complete;
 };
 
index 755743d508aa4582afdbb61a8983499b18a67430..b85eefb230fd26299e2486c71a7dbeec62577406 100644 (file)
@@ -1055,6 +1055,8 @@ struct hci_request {
 void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
 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_add_ev(struct hci_request *req, u16 opcode, u32 plen, void *param,
+                   u8 event);
 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,
index 8b2d543fb1432f2dffbd41b767aa2ed4d7ed8d60..7f1413cae2cbc0292353ab2b60ecf0144220dd92 100644 (file)
@@ -2645,7 +2645,8 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 }
 
 /* Queue a command to an asynchronous HCI request */
-void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param)
+void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, void *param,
+                   u8 event)
 {
        struct hci_dev *hdev = req->hdev;
        struct sk_buff *skb;
@@ -2669,9 +2670,16 @@ void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param)
        if (skb_queue_empty(&req->cmd_q))
                bt_cb(skb)->req.start = true;
 
+       bt_cb(skb)->req.event = event;
+
        skb_queue_tail(&req->cmd_q, skb);
 }
 
+void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param)
+{
+       hci_req_add_ev(req, opcode, plen, param, 0);
+}
+
 /* Get data from the previously sent command */
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
 {
index ed0efb7255b064cb6f520ae9b89925d5e0f71f17..0a2b128d2cc9a9629d81623e5f51c25bcf2b24c2 100644 (file)
@@ -2463,7 +2463,9 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
        if (opcode != HCI_OP_NOP)
                del_timer(&hdev->cmd_timer);
 
-       hci_req_cmd_complete(hdev, opcode, ev->status);
+       if (ev->status ||
+           (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event))
+               hci_req_cmd_complete(hdev, opcode, ev->status);
 
        if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
                atomic_set(&hdev->cmd_cnt, 1);
@@ -3713,6 +3715,13 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 
        skb_pull(skb, HCI_EVENT_HDR_SIZE);
 
+       if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) {
+               struct hci_command_hdr *hdr = (void *) hdev->sent_cmd->data;
+               u16 opcode = __le16_to_cpu(hdr->opcode);
+
+               hci_req_cmd_complete(hdev, opcode, 0);
+       }
+
        switch (event) {
        case HCI_EV_INQUIRY_COMPLETE:
                hci_inquiry_complete_evt(hdev, skb);