[PATCH 03/12 v3] Bluetooth: Add hci_transaction_cmd_complete function

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

 



From: Johan Hedberg <johan.hedberg@xxxxxxxxx>

This function is used to process the HCI transaction state, including
things like picking the next command to send, calling the complete
callback for the current transaction and moving the next transaction
from the queue (if any) to hdev->current_transaction.

Signed-off-by: Johan Hedberg <johan.hedberg@xxxxxxxxx>
---
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/hci_core.c         |   65 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5cd58f5..54efaa2 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1062,6 +1062,7 @@ int hci_start_transaction(struct hci_dev *hdev);
 int hci_complete_transaction(struct hci_dev *hdev,
 			     void (*complete)(struct hci_dev *hdev,
 					      __u16 last_cmd, int status));
+bool hci_transaction_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
 
 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);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0b289f3..8923a1f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2976,6 +2976,71 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 	kfree_skb(skb);
 }
 
+static void __transaction_next(struct hci_dev *hdev, u16 opcode, int status)
+{
+	struct hci_transaction *transaction;
+
+	transaction = hdev->current_transaction;
+	if (!transaction)
+		goto next_in_queue;
+
+	if (status || skb_queue_empty(&transaction->cmd_q)) {
+		hdev->current_transaction = NULL;
+
+		/* We need to give up the transaction lock temporarily
+		 * since the complete callback might trigger a deadlock
+		 */
+		hci_transaction_unlock(hdev);
+		if (transaction->complete)
+			transaction->complete(hdev, opcode, status);
+		__transaction_free(transaction);
+		hci_transaction_lock(hdev);
+
+		transaction = hdev->current_transaction;
+	}
+
+	if (transaction)
+		return;
+
+next_in_queue:
+	if (list_empty(&hdev->transaction_q))
+		return;
+
+	transaction = list_first_entry(&hdev->transaction_q,
+				       struct hci_transaction, list);
+	if (transaction)
+		list_del(&transaction->list);
+
+	hdev->current_transaction = transaction;
+}
+
+bool hci_transaction_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
+{
+	bool queue_empty;
+
+	/* Ignore this event if it doesn't match the last HCI command
+	 * that was sent
+	 */
+	if (!hci_sent_cmd_data(hdev, opcode))
+		return false;
+
+	hci_transaction_lock(hdev);
+
+	__transaction_next(hdev, opcode, status);
+
+	if (!hdev->current_transaction) {
+		queue_empty = true;
+		goto unlock;
+	}
+
+	queue_empty = skb_queue_empty(&hdev->current_transaction->cmd_q);
+
+unlock:
+	hci_transaction_unlock(hdev);
+
+	return queue_empty;
+}
+
 static void hci_rx_work(struct work_struct *work)
 {
 	struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
-- 
1.7.10.4

--
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