Commit 505ea2b2 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz
Browse files

Bluetooth: hci_sync: Add helper functions to manipulate cmd_sync queue



This adds functions to queue, dequeue and lookup into the cmd_sync
list.

Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 5f641f03
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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);
+124 −8
Original line number Diff line number Diff line
@@ -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)