]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: hci_sync: Add helper functions to manipulate cmd_sync queue
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 9 Aug 2023 20:43:53 +0000 (13:43 -0700)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 6 Mar 2024 22:24:05 +0000 (17:24 -0500)
This adds functions to queue, dequeue and lookup into the cmd_sync
list.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci_sync.h
net/bluetooth/hci_sync.c

index ed334c253ebcd928efcdc22cc11b510c526f0d00..4ff4aa68ee196d5e14dc09be5c14cce29ea24498 100644 (file)
@@ -48,6 +48,18 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
                        void *data, hci_cmd_sync_work_destroy_t destroy);
 int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
                       void *data, hci_cmd_sync_work_destroy_t destroy);
+struct hci_cmd_sync_work_entry *
+hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                         void *data, hci_cmd_sync_work_destroy_t destroy);
+int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                           void *data, hci_cmd_sync_work_destroy_t destroy);
+void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
+                              struct hci_cmd_sync_work_entry *entry);
+bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                         void *data, hci_cmd_sync_work_destroy_t destroy);
+bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev,
+                             hci_cmd_sync_work_func_t func, void *data,
+                             hci_cmd_sync_work_destroy_t destroy);
 
 int hci_update_eir_sync(struct hci_dev *hdev);
 int hci_update_class_sync(struct hci_dev *hdev);
index e1fdcb3c270625896bb2e820628ec0c8e3cca9b7..5b314bf844f847976dc23e179bf47d4f496088ea 100644 (file)
@@ -566,6 +566,17 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
        INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
 }
 
+static void _hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
+                                      struct hci_cmd_sync_work_entry *entry,
+                                      int err)
+{
+       if (entry->destroy)
+               entry->destroy(hdev, entry->data, err);
+
+       list_del(&entry->list);
+       kfree(entry);
+}
+
 void hci_cmd_sync_clear(struct hci_dev *hdev)
 {
        struct hci_cmd_sync_work_entry *entry, *tmp;
@@ -574,13 +585,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
        cancel_work_sync(&hdev->reenable_adv_work);
 
        mutex_lock(&hdev->cmd_sync_work_lock);
-       list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
-               if (entry->destroy)
-                       entry->destroy(hdev, entry->data, -ECANCELED);
-
-               list_del(&entry->list);
-               kfree(entry);
-       }
+       list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list)
+               _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
        mutex_unlock(&hdev->cmd_sync_work_lock);
 }
 
@@ -669,6 +675,115 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
 }
 EXPORT_SYMBOL(hci_cmd_sync_queue);
 
+static struct hci_cmd_sync_work_entry *
+_hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                          void *data, hci_cmd_sync_work_destroy_t destroy)
+{
+       struct hci_cmd_sync_work_entry *entry, *tmp;
+
+       list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
+               if (func && entry->func != func)
+                       continue;
+
+               if (data && entry->data != data)
+                       continue;
+
+               if (destroy && entry->destroy != destroy)
+                       continue;
+
+               return entry;
+       }
+
+       return NULL;
+}
+
+/* Queue HCI command entry once:
+ *
+ * - Lookup if an entry already exist and only if it doesn't creates a new entry
+ *   and queue it.
+ */
+int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                           void *data, hci_cmd_sync_work_destroy_t destroy)
+{
+       if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
+               return 0;
+
+       return hci_cmd_sync_queue(hdev, func, data, destroy);
+}
+EXPORT_SYMBOL(hci_cmd_sync_queue_once);
+
+/* Lookup HCI command entry:
+ *
+ * - Return first entry that matches by function callback or data or
+ *   destroy callback.
+ */
+struct hci_cmd_sync_work_entry *
+hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                         void *data, hci_cmd_sync_work_destroy_t destroy)
+{
+       struct hci_cmd_sync_work_entry *entry;
+
+       mutex_lock(&hdev->cmd_sync_work_lock);
+       entry = _hci_cmd_sync_lookup_entry(hdev, func, data, destroy);
+       mutex_unlock(&hdev->cmd_sync_work_lock);
+
+       return entry;
+}
+EXPORT_SYMBOL(hci_cmd_sync_lookup_entry);
+
+/* Cancel HCI command entry */
+void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
+                              struct hci_cmd_sync_work_entry *entry)
+{
+       mutex_lock(&hdev->cmd_sync_work_lock);
+       _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
+       mutex_unlock(&hdev->cmd_sync_work_lock);
+}
+EXPORT_SYMBOL(hci_cmd_sync_cancel_entry);
+
+/* Dequeue one HCI command entry:
+ *
+ * - Lookup and cancel first entry that matches.
+ */
+bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev,
+                              hci_cmd_sync_work_func_t func,
+                              void *data, hci_cmd_sync_work_destroy_t destroy)
+{
+       struct hci_cmd_sync_work_entry *entry;
+
+       entry = hci_cmd_sync_lookup_entry(hdev, func, data, destroy);
+       if (!entry)
+               return false;
+
+       hci_cmd_sync_cancel_entry(hdev, entry);
+
+       return true;
+}
+EXPORT_SYMBOL(hci_cmd_sync_dequeue_once);
+
+/* Dequeue HCI command entry:
+ *
+ * - Lookup and cancel any entry that matches by function callback or data or
+ *   destroy callback.
+ */
+bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                         void *data, hci_cmd_sync_work_destroy_t destroy)
+{
+       struct hci_cmd_sync_work_entry *entry;
+       bool ret = false;
+
+       mutex_lock(&hdev->cmd_sync_work_lock);
+       while ((entry = _hci_cmd_sync_lookup_entry(hdev, func, data,
+                                                  destroy))) {
+               _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
+               ret = true;
+       }
+       mutex_unlock(&hdev->cmd_sync_work_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(hci_cmd_sync_dequeue);
+
 int hci_update_eir_sync(struct hci_dev *hdev)
 {
        struct hci_cp_write_eir cp;
@@ -2881,7 +2996,8 @@ int hci_update_passive_scan(struct hci_dev *hdev)
            hci_dev_test_flag(hdev, HCI_UNREGISTER))
                return 0;
 
-       return hci_cmd_sync_queue(hdev, update_passive_scan_sync, NULL, NULL);
+       return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
+                                      NULL);
 }
 
 int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val)