aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_core.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-04-02 06:41:08 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-04-02 10:09:27 -0400
commite6214487492566b15ff24e97c6747bb2e5d9e040 (patch)
tree6c6a1538555999336070eedfa4648d7463ef3771 /net/bluetooth/hci_core.c
parent444c6dd54d81edf81c606f571cb52eff4d47fa99 (diff)
Bluetooth: Add second hci_request callback option for full skb
This patch adds a second possible callback for HCI requests where the callback will receive the full skb of the last successfully completed HCI command. This API is useful for cases where we want to use a request to read some data and the existing hci_event.c handlers do not store it e.g. in the hci_dev struct. The reason the patch is a bit bigger than just adding the new API is because the hci_req_cmd_complete() functions required some refactoring to enable it: now hci_req_cmd_complete() is simply used to request the callback pointers if any, and the actual calling of them happens from a single place at the end of hci_event_packet(). The reason for this is that we need to pass the original skb (without any skb_pull, etc modifications done to it) and it's simplest to keep track of it within the hci_event_packet() function. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r--net/bluetooth/hci_core.c30
1 files changed, 12 insertions, 18 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 246d7eca5d29..8af3af324eee 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -4288,9 +4288,10 @@ static void hci_resend_last(struct hci_dev *hdev)
4288 queue_work(hdev->workqueue, &hdev->cmd_work); 4288 queue_work(hdev->workqueue, &hdev->cmd_work);
4289} 4289}
4290 4290
4291void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) 4291void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
4292 hci_req_complete_t *req_complete,
4293 hci_req_complete_skb_t *req_complete_skb)
4292{ 4294{
4293 hci_req_complete_t req_complete = NULL;
4294 struct sk_buff *skb; 4295 struct sk_buff *skb;
4295 unsigned long flags; 4296 unsigned long flags;
4296 4297
@@ -4322,18 +4323,14 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
4322 * callback would be found in hdev->sent_cmd instead of the 4323 * callback would be found in hdev->sent_cmd instead of the
4323 * command queue (hdev->cmd_q). 4324 * command queue (hdev->cmd_q).
4324 */ 4325 */
4325 if (hdev->sent_cmd) { 4326 if (bt_cb(hdev->sent_cmd)->req.complete) {
4326 req_complete = bt_cb(hdev->sent_cmd)->req.complete; 4327 *req_complete = bt_cb(hdev->sent_cmd)->req.complete;
4327 4328 return;
4328 if (req_complete) { 4329 }
4329 /* We must set the complete callback to NULL to
4330 * avoid calling the callback more than once if
4331 * this function gets called again.
4332 */
4333 bt_cb(hdev->sent_cmd)->req.complete = NULL;
4334 4330
4335 goto call_complete; 4331 if (bt_cb(hdev->sent_cmd)->req.complete_skb) {
4336 } 4332 *req_complete_skb = bt_cb(hdev->sent_cmd)->req.complete_skb;
4333 return;
4337 } 4334 }
4338 4335
4339 /* Remove all pending commands belonging to this request */ 4336 /* Remove all pending commands belonging to this request */
@@ -4344,14 +4341,11 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
4344 break; 4341 break;
4345 } 4342 }
4346 4343
4347 req_complete = bt_cb(skb)->req.complete; 4344 *req_complete = bt_cb(skb)->req.complete;
4345 *req_complete_skb = bt_cb(skb)->req.complete_skb;
4348 kfree_skb(skb); 4346 kfree_skb(skb);
4349 } 4347 }
4350 spin_unlock_irqrestore(&hdev->cmd_q.lock, flags); 4348 spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
4351
4352call_complete:
4353 if (req_complete)
4354 req_complete(hdev, status, status ? opcode : HCI_OP_NOP);
4355} 4349}
4356 4350
4357static void hci_rx_work(struct work_struct *work) 4351static void hci_rx_work(struct work_struct *work)