Add support for multiple potential adapter_ops implementations

This patch changes the adapter_ops registration procedure to simply add
the callback struct into a list. The actual adapter_ops implementation
that gets used gets chosen in the adapter_ops_setup function.
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 69bb1ae..6624785 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -2341,7 +2341,7 @@
 
 static int hciops_init(void)
 {
-	return btd_register_adapter_ops(&hci_ops);
+	return btd_register_adapter_ops(&hci_ops, FALSE);
 }
 static void hciops_exit(void)
 {
diff --git a/src/adapter.c b/src/adapter.c
index 4a9f34e..b25a7fc 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -72,6 +72,8 @@
 static DBusConnection *connection = NULL;
 static GSList *adapter_drivers = NULL;
 
+static GSList *ops_candidates = NULL;
+
 const struct btd_adapter_ops *adapter_ops = NULL;
 
 struct session_req {
@@ -3574,31 +3576,48 @@
 	return adapter_ops->set_powered(adapter->dev_id, FALSE);
 }
 
-int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops)
+int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority)
 {
-	/* Already registered */
-	if (adapter_ops)
-		return -EALREADY;
-
-	if (btd_adapter_ops->setup == NULL)
+	if (ops->setup == NULL)
 		return -EINVAL;
 
-	adapter_ops = btd_adapter_ops;
+	if (priority)
+		ops_candidates = g_slist_prepend(ops_candidates, ops);
+	else
+		ops_candidates = g_slist_append(ops_candidates, ops);
 
 	return 0;
 }
 
-void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops)
+void btd_adapter_cleanup_ops(struct btd_adapter_ops *ops)
 {
-	adapter_ops->cleanup();
+	ops_candidates = g_slist_remove(ops_candidates, ops);
+	ops->cleanup();
+
+	if (adapter_ops == ops)
+		adapter_ops = NULL;
 }
 
 int adapter_ops_setup(void)
 {
-	if (!adapter_ops)
+	GSList *l;
+	int ret;
+
+	if (!ops_candidates)
 		return -EINVAL;
 
-	return adapter_ops->setup();
+	for (l = ops_candidates; l != NULL; l = g_slist_next(l)) {
+		struct btd_adapter_ops *ops = l->data;
+
+		ret = ops->setup();
+		if (ret < 0)
+			continue;
+
+		adapter_ops = ops;
+		break;
+	}
+
+	return ret;
 }
 
 void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
diff --git a/src/adapter.h b/src/adapter.h
index a2466d3..aa4d686 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -233,7 +233,7 @@
 							gpointer user_data);
 };
 
-int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
+int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
 void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops);
 int adapter_ops_setup(void);