Refactor adapter initialization and power control

This (rather big) patch refactors the way that adapters are initialized
and powered on/off. The purpose is to align the adapter_ops <-> core
daemon interface with how the management interface will behave.
diff --git a/plugins/hciops.c b/plugins/hciops.c
index c364ef2..5ed871b 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -72,6 +72,8 @@
 #define WANTED_COD(index) devs[(index)].wanted_cod
 #define PENDING_COD(index) devs[(index)].pending_cod
 #define CACHE_ENABLE(index) devs[(index)].cache_enable
+#define ALREADY_UP(index) devs[(index)].already_up
+#define REGISTERED(index) devs[(index)].registered
 #define VER(index) devs[(index)].ver
 #define DID_VENDOR(index) devs[(index)].did_vendor
 #define DID_PRODUCT(index) devs[(index)].did_product
@@ -97,6 +99,8 @@
 	uint32_t wanted_cod;
 	uint32_t pending_cod;
 	gboolean cache_enable;
+	gboolean already_up;
+	gboolean registered;
 
 	struct hci_version ver;
 
@@ -117,12 +121,13 @@
 	return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR;
 }
 
-static void init_dev_info(int index, int sk)
+static void init_dev_info(int index, int sk, gboolean registered)
 {
 	memset(&devs[index], 0, sizeof(struct dev_info));
 	SK(index) = sk;
 	PIN_LENGTH(index) = -1;
 	CACHE_ENABLE(index) = TRUE;
+	REGISTERED(index) = registered;
 }
 
 /* Async HCI command handling with callback support */
@@ -293,6 +298,49 @@
 	return 0;
 }
 
+static int hciops_set_discoverable(int index, gboolean discoverable)
+{
+	uint8_t mode;
+
+	if (discoverable)
+		mode = (SCAN_PAGE | SCAN_INQUIRY);
+	else
+		mode = SCAN_PAGE;
+
+	DBG("hci%d discoverable %d", index, discoverable);
+
+	if (hci_send_cmd(SK(index), OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+								1, &mode) < 0)
+		return -errno;
+
+	return 0;
+}
+
+static int hciops_stop(int index)
+{
+	int err = 0;
+
+	DBG("hci%d", index);
+
+	if (ioctl(SK(index), HCIDEVDOWN, index) == 0)
+		goto done; /* on success */
+
+	if (errno != EALREADY) {
+		err = -errno;
+		error("Can't stop device hci%d: %s (%d)",
+				index, strerror(-err), -err);
+	}
+
+done:
+	return err;
+}
+
+static int hciops_set_pairable(int index, gboolean pairable)
+{
+	DBG("hci%d pairable %d", index, pairable);
+	return -ENOSYS;
+}
+
 static void start_adapter(int index)
 {
 	uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 };
@@ -346,7 +394,6 @@
 		hci_send_cmd(SK(index), OGF_HOST_CTL,
 				OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
 
-
 	/* Set default link policy */
 	link_policy = main_opts.link_policy;
 
@@ -365,8 +412,49 @@
 
 	CURRENT_COD(index) = 0;
 	memset(EIR(index), 0, sizeof(EIR(index)));
+}
 
-	manager_start_adapter(index);
+static gboolean init_adapter(int index)
+{
+	struct btd_adapter *adapter = NULL;
+	gboolean existing_adapter = REGISTERED(index);
+	uint8_t mode, on_mode;
+	gboolean pairable, discoverable;
+
+	if (!REGISTERED(index)) {
+		adapter = btd_manager_register_adapter(index);
+		if (adapter)
+			REGISTERED(index) = TRUE;
+	} else {
+		adapter = manager_find_adapter(&BDADDR(index));
+		/* FIXME: manager_find_adapter should return a new ref */
+		btd_adapter_ref(adapter);
+	}
+
+	if (adapter == NULL)
+		return FALSE;
+
+	btd_adapter_get_state(adapter, &mode, &on_mode, &pairable);
+
+	if (existing_adapter)
+		mode = on_mode;
+
+	if (mode == MODE_OFF) {
+		hciops_stop(index);
+		goto done;
+	}
+
+	start_adapter(index);
+	btd_adapter_start(adapter);
+
+	discoverable = (mode == MODE_DISCOVERABLE);
+
+	hciops_set_discoverable(index, discoverable);
+	hciops_set_pairable(index, pairable);
+
+done:
+	btd_adapter_unref(adapter);
+	return TRUE;
 }
 
 static int hciops_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
@@ -908,7 +996,7 @@
 	DBG("Got version for hci%d", index);
 
 	if (!PENDING(index) && UP(index))
-		start_adapter(index);
+		init_adapter(index);
 }
 
 static void read_local_features_complete(int index,
@@ -927,7 +1015,7 @@
 	DBG("Got features for hci%d", index);
 
 	if (!PENDING(index) && UP(index))
-		start_adapter(index);
+		init_adapter(index);
 }
 
 #define SIZEOF_UUID128 16
@@ -1178,7 +1266,7 @@
 					OCF_READ_LOCAL_VERSION, 0, NULL);
 
 	if (!PENDING(index))
-		start_adapter(index);
+		init_adapter(index);
 }
 
 static void read_tx_power_complete(int index, void *ptr)
@@ -1256,7 +1344,7 @@
 	DBG("Got bdaddr for hci%d", index);
 
 	if (!PENDING(index) && UP(index))
-		start_adapter(index);
+		init_adapter(index);
 }
 
 static inline void cmd_status(int index, void *ptr)
@@ -1729,7 +1817,7 @@
 	g_source_remove(WATCH_ID(index));
 	g_io_channel_unref(CHANNEL(index));
 	hci_close_dev(SK(index));
-	init_dev_info(index, -1);
+	init_dev_info(index, -1, REGISTERED(index));
 }
 
 static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
@@ -1995,7 +2083,7 @@
 			READ_STORED_LINK_KEY_CP_SIZE, (void *) &cp);
 
 	if (!PENDING(index))
-		start_adapter(index);
+		init_adapter(index);
 }
 
 static void init_pending(int index)
@@ -2026,7 +2114,7 @@
 		devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));
 	}
 
-	init_dev_info(index, dd);
+	init_dev_info(index, dd, FALSE);
 	init_pending(index);
 	start_hci_dev(index);
 
@@ -2071,7 +2159,6 @@
 static void device_devreg_setup(int index)
 {
 	struct hci_dev_info di;
-	gboolean devup;
 
 	DBG("hci%d", index);
 
@@ -2082,10 +2169,10 @@
 	if (hci_devinfo(index, &di) < 0)
 		return;
 
-	devup = hci_test_bit(HCI_UP, &di.flags);
+	if (ignore_device(&di))
+		return;
 
-	if (!ignore_device(&di))
-		manager_register_adapter(index, devup);
+	ALREADY_UP(index) = hci_test_bit(HCI_UP, &di.flags);
 }
 
 static void device_event(int event, int index)
@@ -2094,12 +2181,15 @@
 	case HCI_DEV_REG:
 		info("HCI dev %d registered", index);
 		device_devreg_setup(index);
+		if (ALREADY_UP(index))
+			device_event(HCI_DEV_UP, index);
 		break;
 
 	case HCI_DEV_UNREG:
 		info("HCI dev %d unregistered", index);
 		stop_hci_dev(index);
-		manager_unregister_adapter(index);
+		if (REGISTERED(index))
+			btd_manager_unregister_adapter(index);
 		break;
 
 	case HCI_DEV_UP:
@@ -2121,6 +2211,28 @@
 	}
 }
 
+static int hciops_stop_inquiry(int index)
+{
+	struct hci_dev_info di;
+	int err;
+
+	DBG("hci%d", index);
+
+	if (hci_devinfo(index, &di) < 0)
+		return -errno;
+
+	if (hci_test_bit(HCI_INQUIRY, &di.flags))
+		err = hci_send_cmd(SK(index), OGF_LINK_CTL,
+						OCF_INQUIRY_CANCEL, 0, 0);
+	else
+		err = hci_send_cmd(SK(index), OGF_LINK_CTL,
+					OCF_EXIT_PERIODIC_INQUIRY, 0, 0);
+	if (err < 0)
+		err = -errno;
+
+	return err;
+}
+
 static gboolean init_known_adapters(gpointer user_data)
 {
 	struct hci_dev_list_req *dl;
@@ -2151,9 +2263,13 @@
 	for (i = 0; i < dl->dev_num; i++, dr++) {
 		device_event(HCI_DEV_REG, dr->dev_id);
 
-		if (!hci_test_bit(HCI_UP, &dr->dev_opt))
+		ALREADY_UP(dr->dev_id) = hci_test_bit(HCI_UP, &dr->dev_opt);
+
+		if (!ALREADY_UP(dr->dev_id))
 			continue;
 
+		hciops_stop_inquiry(dr->dev_id);
+
 		PENDING(dr->dev_id) = 0;
 		hci_set_bit(PENDING_VERSION, &PENDING(dr->dev_id));
 		hci_send_cmd(SK(dr->dev_id), OGF_INFO_PARAM,
@@ -2331,25 +2447,6 @@
 	return err;
 }
 
-static int hciops_stop(int index)
-{
-	int err = 0;
-
-	DBG("hci%d", index);
-
-	if (ioctl(SK(index), HCIDEVDOWN, index) == 0)
-		goto done; /* on success */
-
-	if (errno != EALREADY) {
-		err = -errno;
-		error("Can't stop device hci%d: %s (%d)",
-				index, strerror(-err), -err);
-	}
-
-done:
-	return err;
-}
-
 static int hciops_set_powered(int index, gboolean powered)
 {
 	uint8_t mode = SCAN_DISABLED;
@@ -2366,11 +2463,16 @@
 	return hciops_stop(index);
 }
 
-static int hciops_connectable(int index)
+static int hciops_set_connectable(int index, gboolean connectable)
 {
-	uint8_t mode = SCAN_PAGE;
+	uint8_t mode;
 
-	DBG("hci%d", index);
+	if (connectable)
+		mode = SCAN_PAGE;
+	else
+		mode = 0x00;
+
+	DBG("hci%d connectable %d", index, connectable);
 
 	if (hci_send_cmd(SK(index), OGF_HOST_CTL,
 					OCF_WRITE_SCAN_ENABLE, 1, &mode) < 0)
@@ -2379,23 +2481,12 @@
 	return 0;
 }
 
-static int hciops_discoverable(int index)
-{
-	uint8_t mode = (SCAN_PAGE | SCAN_INQUIRY);
-
-	DBG("hci%d", index);
-
-	if (hci_send_cmd(SK(index), OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
-								1, &mode) < 0)
-		return -errno;
-
-	return 0;
-}
-
 static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
 {
 	int err;
 
+	DBG("hci%d major %u minor %u", index, major, minor);
+
 	/* Update only the major and minor class bits keeping remaining bits
 	 * intact*/
 	WANTED_COD(index) &= 0xffe000;
@@ -2453,28 +2544,6 @@
 	return err;
 }
 
-static int hciops_stop_inquiry(int index)
-{
-	struct hci_dev_info di;
-	int err;
-
-	DBG("hci%d", index);
-
-	if (hci_devinfo(index, &di) < 0)
-		return -errno;
-
-	if (hci_test_bit(HCI_INQUIRY, &di.flags))
-		err = hci_send_cmd(SK(index), OGF_LINK_CTL,
-						OCF_INQUIRY_CANCEL, 0, 0);
-	else
-		err = hci_send_cmd(SK(index), OGF_LINK_CTL,
-					OCF_EXIT_PERIODIC_INQUIRY, 0, 0);
-	if (err < 0)
-		err = -errno;
-
-	return err;
-}
-
 static int le_set_scan_enable(int index, uint8_t enable)
 {
 	le_set_scan_enable_cp cp;
@@ -2900,15 +2969,17 @@
 	return 0;
 }
 
-static int hciops_write_le_host(int index, uint8_t le, uint8_t simul)
+static int hciops_enable_le(int index)
 {
 	write_le_host_supported_cp cp;
 
-	DBG("hci%d le %u simul %u", index, le, simul);
+	DBG("hci%d", index);
 
-	memset(&cp, 0, sizeof(cp));
-	cp.le = le;
-	cp.simul = simul;
+	if (!(FEATURES(index)[4] & LMP_LE))
+		return -ENOTSUP;
+
+	cp.le = 0x01;
+	cp.simul = (FEATURES(index)[6] & LMP_LE_BREDR) ? 0x01 : 0x00;
 
 	if (hci_send_cmd(SK(index), OGF_HOST_CTL,
 				OCF_WRITE_LE_HOST_SUPPORTED,
@@ -2966,6 +3037,8 @@
 {
 	int err;
 
+	DBG("hci%d value %u", index, value);
+
 	/* Update only the service class, keep the limited bit,
 	 * major/minor class bits intact */
 	WANTED_COD(index) &= 0x00ffff;
@@ -3005,7 +3078,7 @@
 		return -ENODEV;
 
 	for (list = adapter_get_services(adapter); list; list = list->next) {
-		sdp_record_t *rec = list->data;
+                sdp_record_t *rec = list->data;
 
 		if (rec->svclass.type != SDP_UUID16)
 			continue;
@@ -3080,14 +3153,23 @@
 	return write_class(index, WANTED_COD(index));
 }
 
+static int hciops_restore_powered(int index)
+{
+	if (!ALREADY_UP(index) && UP(index))
+		return hciops_stop(index);
+
+	return 0;
+}
+
 static struct btd_adapter_ops hci_ops = {
 	.setup = hciops_setup,
 	.cleanup = hciops_cleanup,
 	.start = hciops_start,
 	.stop = hciops_stop,
 	.set_powered = hciops_set_powered,
-	.set_connectable = hciops_connectable,
-	.set_discoverable = hciops_discoverable,
+	.set_connectable = hciops_set_connectable,
+	.set_discoverable = hciops_set_discoverable,
+	.set_pairable = hciops_set_pairable,
 	.set_limited_discoverable = hciops_set_limited_discoverable,
 	.start_inquiry = hciops_start_inquiry,
 	.stop_inquiry = hciops_stop_inquiry,
@@ -3115,12 +3197,13 @@
 	.passkey_reply = hciops_passkey_reply,
 	.get_auth_info = hciops_get_auth_info,
 	.read_scan_enable = hciops_read_scan_enable,
-	.write_le_host = hciops_write_le_host,
+	.enable_le = hciops_enable_le,
 	.get_remote_version = hciops_get_remote_version,
 	.encrypt_link = hciops_encrypt_link,
 	.set_did = hciops_set_did,
 	.services_updated = hciops_services_updated,
 	.disable_cod_cache = hciops_disable_cod_cache,
+	.restore_powered = hciops_restore_powered,
 };
 
 static int hciops_init(void)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index a7117fa..8320981 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -149,7 +149,7 @@
 	if (!controllers[index].valid)
 		return;
 
-	manager_unregister_adapter(index);
+	btd_manager_unregister_adapter(index);
 
 	memset(&controllers[index], 0, sizeof(struct controller_info));
 
@@ -221,10 +221,31 @@
 	}
 }
 
+static int mgmt_stop(int index)
+{
+	DBG("index %d", index);
+	return -ENOSYS;
+}
+
+static int mgmt_set_discoverable(int index, gboolean discoverable)
+{
+	DBG("index %d discoverable %d", index, discoverable);
+	return -ENOSYS;
+}
+
+static int mgmt_set_pairable(int index, gboolean pairable)
+{
+	DBG("index %d pairable %d", index, pairable);
+	return -ENOSYS;
+}
+
 static void read_info_complete(int sk, void *buf, size_t len)
 {
 	struct mgmt_rp_read_info *rp = buf;
 	struct controller_info *info;
+	struct btd_adapter *adapter;
+	uint8_t mode;
+	gboolean pairable, discoverable;
 	uint16_t index;
 	char addr[18];
 
@@ -262,10 +283,30 @@
 					info->enabled, info->discoverable,
 					info->pairable, info->sec_mode);
 
-	manager_register_adapter(index, info->enabled);
+	adapter = btd_manager_register_adapter(index);
+	if (adapter == NULL) {
+		error("mgmtops: unable to register adapter");
+		return;
+	}
+
+	btd_adapter_get_state(adapter, &mode, NULL, &pairable);
+	if (mode == MODE_OFF) {
+		mgmt_stop(index);
+		return;
+	}
+
+	discoverable = (mode == MODE_DISCOVERABLE);
+
+	if (info->discoverable != discoverable)
+		mgmt_set_discoverable(index, discoverable);
+
+	if (info->pairable != pairable)
+		mgmt_set_pairable(index, pairable);
 
 	if (info->enabled)
-		manager_start_adapter(index);
+		btd_adapter_start(adapter);
+
+	btd_adapter_unref(adapter);
 }
 
 static void mgmt_cmd_complete(int sk, void *buf, size_t len)
@@ -465,27 +506,15 @@
 	return -ENOSYS;
 }
 
-static int mgmt_stop(int index)
-{
-	DBG("index %d", index);
-	return -ENOSYS;
-}
-
 static int mgmt_set_powered(int index, gboolean powered)
 {
 	DBG("index %d powered %d", index, powered);
 	return -ENOSYS;
 }
 
-static int mgmt_connectable(int index)
+static int mgmt_set_connectable(int index, gboolean connectable)
 {
-	DBG("index %d", index);
-	return -ENOSYS;
-}
-
-static int mgmt_discoverable(int index)
-{
-	DBG("index %d", index);
+	DBG("index %d connectable %d", index, connectable);
 	return -ENOSYS;
 }
 
@@ -722,9 +751,9 @@
 	return -ENOSYS;
 }
 
-static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul)
+static int mgmt_enable_le(int index)
 {
-	DBG("index %d le %u simul %u", index, le, simul);
+	DBG("index %d", index);
 	return -ENOSYS;
 }
 
@@ -752,8 +781,9 @@
 	.start = mgmt_start,
 	.stop = mgmt_stop,
 	.set_powered = mgmt_set_powered,
-	.set_connectable = mgmt_connectable,
-	.set_discoverable = mgmt_discoverable,
+	.set_connectable = mgmt_set_connectable,
+	.set_discoverable = mgmt_set_discoverable,
+	.set_pairable = mgmt_set_pairable,
 	.set_limited_discoverable = mgmt_set_limited_discoverable,
 	.start_inquiry = mgmt_start_inquiry,
 	.stop_inquiry = mgmt_stop_inquiry,
@@ -781,7 +811,7 @@
 	.passkey_reply = mgmt_passkey_reply,
 	.get_auth_info = mgmt_get_auth_info,
 	.read_scan_enable = mgmt_read_scan_enable,
-	.write_le_host = mgmt_write_le_host,
+	.enable_le = mgmt_enable_le,
 	.get_remote_version = mgmt_get_remote_version,
 	.encrypt_link = mgmt_encrypt_link,
 };
diff --git a/src/adapter.c b/src/adapter.c
index 5118306..8c48501 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -125,9 +125,6 @@
 	struct hci_dev dev;		/* hci info */
 	gboolean pairable;		/* pairable state */
 
-	gboolean initialized;
-	gboolean already_up;		/* adapter was already up on init */
-
 	gboolean off_requested;		/* DEVDOWN ioctl was called */
 
 	gint ref;
@@ -352,7 +349,7 @@
 
 	adapter->discov_timeout_id = 0;
 
-	adapter_ops->set_connectable(adapter->dev_id);
+	adapter_ops->set_connectable(adapter->dev_id, TRUE);
 
 	return FALSE;
 }
@@ -421,9 +418,9 @@
 	int err;
 
 	if (mode == MODE_CONNECTABLE)
-		err = adapter_ops->set_connectable(adapter->dev_id);
+		err = adapter_ops->set_connectable(adapter->dev_id, TRUE);
 	else
-		err = adapter_ops->set_discoverable(adapter->dev_id);
+		err = adapter_ops->set_discoverable(adapter->dev_id, TRUE);
 
 	if (err < 0)
 		return err;
@@ -555,9 +552,10 @@
 		return btd_error_failed(msg, strerror(-err));
 
 store:
-
 	adapter->pairable = pairable;
 
+	adapter_ops->set_pairable(adapter->dev_id, pairable);
+
 	write_device_pairable(&adapter->bdaddr, pairable);
 
 	emit_property_changed(connection, adapter->path,
@@ -1832,47 +1830,6 @@
 	{ }
 };
 
-static int adapter_setup(struct btd_adapter *adapter, const char *mode)
-{
-	struct hci_dev *dev = &adapter->dev;
-	int err;
-	char name[MAX_NAME_LENGTH + 1];
-	uint8_t cls[3];
-
-	if ((dev->features[4] & LMP_LE) && main_opts.le) {
-		uint8_t simul = (dev->features[6] & LMP_LE_BREDR) ? 0x01 : 0x00;
-		err = adapter_ops->write_le_host(adapter->dev_id, 0x01, simul);
-		if (err < 0) {
-			error("Can't write LE host supported for %s: %s(%d)",
-					adapter->path, strerror(-err), -err);
-			return err;
-		}
-	}
-
-	if (read_local_name(&adapter->bdaddr, name) < 0)
-		expand_name(name, MAX_NAME_LENGTH, main_opts.name,
-							adapter->dev_id);
-
-	adapter_ops->set_name(adapter->dev_id, name);
-	if (g_str_equal(mode, "off"))
-		strncpy((char *) adapter->dev.name, name, MAX_NAME_LENGTH);
-
-	if (adapter->initialized)
-		return 0;
-
-	if (read_local_class(&adapter->bdaddr, cls) < 0) {
-		uint32_t class = htobl(main_opts.class);
-		if (class)
-			memcpy(cls, &class, 3);
-		else
-			return 0;
-	}
-
-	btd_adapter_set_class(adapter, cls[1], cls[0]);
-
-	return 0;
-}
-
 static void create_stored_device_from_profiles(char *key, char *value,
 						void *user_data)
 {
@@ -2117,75 +2074,65 @@
 	return type;
 }
 
-static int adapter_up(struct btd_adapter *adapter, const char *mode)
+void btd_adapter_get_state(struct btd_adapter *adapter, uint8_t *mode,
+					uint8_t *on_mode, gboolean *pairable)
 {
-	char srcaddr[18];
-	gboolean powered, dev_down = FALSE;
-	int err;
+	char str[14], address[18];
 
-	ba2str(&adapter->bdaddr, srcaddr);
+	ba2str(&adapter->bdaddr, address);
 
-	adapter->off_requested = FALSE;
-	adapter->up = 1;
-	adapter->discov_timeout = get_discoverable_timeout(srcaddr);
-	adapter->pairable_timeout = get_pairable_timeout(srcaddr);
-	adapter->state = STATE_IDLE;
-	adapter->mode = MODE_CONNECTABLE;
-	powered = TRUE;
-
-	/* Set pairable mode */
-	if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
-		adapter->pairable = TRUE;
-
-	if (g_str_equal(mode, "off")) {
-		char onmode[14];
-
-		powered = FALSE;
-
-		if (!adapter->initialized) {
-			dev_down = TRUE;
-			goto proceed;
-		}
-
-		if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0 ||
-						g_str_equal(onmode, "off"))
-			strcpy(onmode, "connectable");
-
-		write_device_mode(&adapter->bdaddr, onmode);
-
-		return adapter_up(adapter, onmode);
-	} else if (!g_str_equal(mode, "connectable"))
-		adapter->mode = MODE_DISCOVERABLE;
-
-proceed:
-	err = adapter_set_mode(adapter, adapter->mode);
-
-	if (err < 0)
-		return err;
-
-	if (adapter->initialized == FALSE) {
-		sdp_init_services_list(&adapter->bdaddr);
-		btd_adapter_services_updated(adapter);
-		load_drivers(adapter);
-		clear_blocked(adapter);
-		load_devices(adapter);
-
-		/* retrieve the active connections: address the scenario where
-		 * the are active connections before the daemon've started */
-		load_connections(adapter);
-
-		adapter->initialized = TRUE;
-
-		manager_add_adapter(adapter->path);
-
+	if (mode) {
+		if (main_opts.remember_powered == FALSE)
+			*mode = main_opts.mode;
+		else if (read_device_mode(address, str, sizeof(str)) < 0)
+			*mode = main_opts.mode;
+		else
+			*mode = get_mode(&adapter->bdaddr, str);
 	}
 
-	if (dev_down) {
-		adapter_ops->stop(adapter->dev_id);
-		adapter->off_requested = TRUE;
-		return 1;
-	} else
-		emit_property_changed(connection, adapter->path,
+	if (on_mode) {
+		if (main_opts.remember_powered == FALSE)
+			*on_mode = main_opts.mode;
+		else if (read_on_mode(address, str, sizeof(str)) < 0)
+			*on_mode = main_opts.mode;
+		else
+			*on_mode = get_mode(&adapter->bdaddr, str);
+	}
+
+	if (pairable)
+		*pairable = adapter->pairable;
+}
+
+void btd_adapter_start(struct btd_adapter *adapter)
+{
+	char address[18];
+	uint8_t cls[3];
+	gboolean powered;
+
+	ba2str(&adapter->bdaddr, address);
+
+	adapter->dev_class = 0;
+	adapter->off_requested = FALSE;
+	adapter->up = TRUE;
+	adapter->discov_timeout = get_discoverable_timeout(address);
+	adapter->pairable_timeout = get_pairable_timeout(address);
+	adapter->state = STATE_IDLE;
+	adapter->mode = MODE_CONNECTABLE;
+
+	if (main_opts.le)
+		adapter_ops->enable_le(adapter->dev_id);
+
+	adapter_ops->set_name(adapter->dev_id, adapter->dev.name);
+
+	if (read_local_class(&adapter->bdaddr, cls) < 0) {
+		uint32_t class = htobl(main_opts.class);
+		memcpy(cls, &class, 3);
+	}
+
+	btd_adapter_set_class(adapter, cls[1], cls[0]);
+
+	powered = TRUE;
+	emit_property_changed(connection, adapter->path,
 					ADAPTER_INTERFACE, "Powered",
 					DBUS_TYPE_BOOLEAN, &powered);
 
@@ -2193,71 +2140,7 @@
 
 	adapter_ops->disable_cod_cache(adapter->dev_id);
 
-	return 0;
-}
-
-int adapter_start(struct btd_adapter *adapter)
-{
-	struct hci_dev *dev = &adapter->dev;
-	struct hci_version ver;
-	uint8_t features[8];
-	int err;
-	char mode[14], address[18];
-
-	if (!bacmp(&adapter->bdaddr, BDADDR_ANY)) {
-		int err;
-
-		err = adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
-		if (err < 0)
-			return err;
-	}
-
-	ba2str(&adapter->bdaddr, address);
-
-	err = read_device_mode(address, mode, sizeof(mode));
-
-	if ((!adapter->initialized && !main_opts.remember_powered) || err < 0) {
-		if (!adapter->initialized && main_opts.mode == MODE_OFF)
-			strcpy(mode, "off");
-		else
-			strcpy(mode, "connectable");
-	}
-
-	err = adapter_ops->read_local_version(adapter->dev_id, &ver);
-	if (err < 0) {
-		error("Can't read version info for %s: %s (%d)",
-					adapter->path, strerror(-err), -err);
-		return err;
-	}
-
-	dev->hci_rev = ver.hci_rev;
-	dev->lmp_ver = ver.lmp_ver;
-	dev->lmp_subver = ver.lmp_subver;
-	dev->manufacturer = ver.manufacturer;
-
-	err = adapter_ops->read_local_features(adapter->dev_id, features);
-	if (err < 0) {
-		error("Can't read features for %s: %s (%d)",
-					adapter->path, strerror(-err), -err);
-		return err;
-	}
-
-	memcpy(dev->features, features, 8);
-
-	adapter->dev_class = 0;
-
-	adapter_setup(adapter, mode);
-
-	if (!adapter->initialized && adapter->already_up) {
-		DBG("Stopping Inquiry at adapter startup");
-		adapter_ops->stop_inquiry(adapter->dev_id);
-	}
-
-	err = adapter_up(adapter, mode);
-
 	info("Adapter %s has been enabled", adapter->path);
-
-	return err;
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2330,7 +2213,7 @@
 	session_unref(pending);
 }
 
-int adapter_stop(struct btd_adapter *adapter)
+int btd_adapter_stop(struct btd_adapter *adapter)
 {
 	gboolean powered, discoverable, pairable;
 
@@ -2445,8 +2328,66 @@
 	g_free(path);
 }
 
-struct btd_adapter *adapter_create(DBusConnection *conn, int id,
-				gboolean devup)
+gboolean adapter_init(struct btd_adapter *adapter)
+{
+	struct hci_version ver;
+	struct hci_dev *dev;
+	int err;
+
+	/* adapter_ops makes sure that newly registered adapters always
+	 * start off as powered */
+	adapter->up = TRUE;
+
+	adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
+
+	if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
+		error("No address available for hci%d", adapter->dev_id);
+		return FALSE;
+	}
+
+	err = adapter_ops->read_local_version(adapter->dev_id, &ver);
+	if (err < 0) {
+		error("Can't read version info for hci%d: %s (%d)",
+					adapter->dev_id, strerror(-err), -err);
+		return FALSE;
+	}
+
+	dev = &adapter->dev;
+
+	dev->hci_rev = ver.hci_rev;
+	dev->lmp_ver = ver.lmp_ver;
+	dev->lmp_subver = ver.lmp_subver;
+	dev->manufacturer = ver.manufacturer;
+
+	err = adapter_ops->read_local_features(adapter->dev_id, dev->features);
+	if (err < 0) {
+		error("Can't read features for hci%d: %s (%d)",
+					adapter->dev_id, strerror(-err), -err);
+		return FALSE;
+	}
+
+	if (read_local_name(&adapter->bdaddr, adapter->dev.name) < 0)
+		expand_name(adapter->dev.name, MAX_NAME_LENGTH, main_opts.name,
+							adapter->dev_id);
+
+	sdp_init_services_list(&adapter->bdaddr);
+	btd_adapter_services_updated(adapter);
+	load_drivers(adapter);
+	clear_blocked(adapter);
+	load_devices(adapter);
+
+	/* Set pairable mode */
+	if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
+		adapter->pairable = TRUE;
+
+	/* retrieve the active connections: address the scenario where
+	 * the are active connections before the daemon've started */
+	load_connections(adapter);
+
+	return TRUE;
+}
+
+struct btd_adapter *adapter_create(DBusConnection *conn, int id)
 {
 	char path[MAX_PATH_LENGTH];
 	struct btd_adapter *adapter;
@@ -2455,21 +2396,20 @@
 	if (!connection)
 		connection = conn;
 
-	snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
-
 	adapter = g_try_new0(struct btd_adapter, 1);
 	if (!adapter) {
-		error("adapter_create: failed to alloc memory for %s", path);
+		error("adapter_create: failed to alloc memory for hci%d", id);
 		return NULL;
 	}
 
 	adapter->dev_id = id;
+
+	snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
 	adapter->path = g_strdup(path);
-	adapter->already_up = devup;
 
 	if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE,
-			adapter_methods, adapter_signals, NULL,
-			adapter, adapter_free)) {
+					adapter_methods, adapter_signals, NULL,
+					adapter, adapter_free)) {
 		error("Adapter interface init failed on path %s", path);
 		adapter_free(adapter);
 		return NULL;
@@ -2488,12 +2428,10 @@
 		device_remove(l->data, FALSE);
 	g_slist_free(adapter->devices);
 
-	if (adapter->initialized)
-		unload_drivers(adapter);
+	unload_drivers(adapter);
 
 	/* Return adapter to down state if it was not up on init */
-	if (adapter->up && !adapter->already_up)
-		adapter_ops->stop(adapter->dev_id);
+	adapter_ops->restore_powered(adapter->dev_id);
 
 	btd_adapter_unref(adapter);
 }
@@ -2594,11 +2532,6 @@
 	return adapter->state;
 }
 
-gboolean adapter_is_ready(struct btd_adapter *adapter)
-{
-	return adapter->initialized;
-}
-
 struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
 						struct remote_dev_info *match)
 {
diff --git a/src/adapter.h b/src/adapter.h
index a02f61c..a7d17ae 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -31,6 +31,11 @@
 
 #define ADAPTER_INTERFACE	"org.bluez.Adapter"
 
+#define MODE_OFF		0x00
+#define MODE_CONNECTABLE	0x01
+#define MODE_DISCOVERABLE	0x02
+#define MODE_UNKNOWN		0xff
+
 /* Discover states */
 #define STATE_IDLE		0x00
 #define STATE_LE_SCAN		0x01
@@ -90,9 +95,12 @@
 	char     name[MAX_NAME_LENGTH + 1];
 };
 
-int adapter_start(struct btd_adapter *adapter);
+void btd_adapter_start(struct btd_adapter *adapter);
 
-int adapter_stop(struct btd_adapter *adapter);
+int btd_adapter_stop(struct btd_adapter *adapter);
+
+void btd_adapter_get_state(struct btd_adapter *adapter, uint8_t *mode,
+					uint8_t *on_mode, gboolean *pairable);
 
 int adapter_set_service_classes(struct btd_adapter *adapter, uint8_t value);
 
@@ -111,9 +119,10 @@
 
 int adapter_resolve_names(struct btd_adapter *adapter);
 
-struct btd_adapter *adapter_create(DBusConnection *conn, int id,
-				gboolean devup);
+struct btd_adapter *adapter_create(DBusConnection *conn, int id);
+gboolean adapter_init(struct btd_adapter *adapter);
 void adapter_remove(struct btd_adapter *adapter);
+uint8_t btd_adapter_get_init_mode(struct btd_adapter *adapter);
 uint16_t adapter_get_dev_id(struct btd_adapter *adapter);
 const gchar *adapter_get_path(struct btd_adapter *adapter);
 void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
@@ -190,8 +199,9 @@
 	int (*start) (int index);
 	int (*stop) (int index);
 	int (*set_powered) (int index, gboolean powered);
-	int (*set_connectable) (int index);
-	int (*set_discoverable) (int index);
+	int (*set_connectable) (int index, gboolean connectable);
+	int (*set_discoverable) (int index, gboolean discoverable);
+	int (*set_pairable) (int index, gboolean pairable);
 	int (*set_limited_discoverable) (int index, gboolean limited);
 	int (*start_inquiry) (int index, uint8_t length, gboolean periodic);
 	int (*stop_inquiry) (int index);
@@ -221,7 +231,7 @@
 	int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint32_t passkey);
 	int (*get_auth_info) (int index, bdaddr_t *bdaddr, uint8_t *auth);
 	int (*read_scan_enable) (int index);
-	int (*write_le_host) (int index, uint8_t le, uint8_t simul);
+	int (*enable_le) (int index);
 	int (*get_remote_version) (int index, uint16_t handle,
 						gboolean delayed);
 	int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb,
@@ -230,6 +240,7 @@
 							uint16_t version);
 	int (*services_updated) (int index);
 	int (*disable_cod_cache) (int index);
+	int (*restore_powered) (int index);
 };
 
 int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
diff --git a/src/hcid.h b/src/hcid.h
index 2e16328..856723b 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -23,21 +23,6 @@
  *
  */
 
-/*
- * Scanning modes, used by DEV_SET_MODE
- * off: remote devices are not allowed to find or connect to this device
- * connectable: remote devices are allowed to connect, but they are not
- *              allowed to find it.
- * discoverable: remote devices are allowed to connect and find this device
- * limited: limited discoverable - GIAC + IAC enabled and set limited
- *          bit on device class.
- */
-
-#define MODE_OFF		0x00
-#define MODE_CONNECTABLE	0x01
-#define MODE_DISCOVERABLE	0x02
-#define MODE_UNKNOWN		0xff
-
 struct main_opts {
 	char		host_name[40];
 	unsigned long	flags;
diff --git a/src/manager.c b/src/manager.c
index c8ec7e5..5421385 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -179,9 +179,6 @@
 	for (i = 0, list = adapters; list; list = list->next) {
 		struct btd_adapter *adapter = list->data;
 
-		if (!adapter_is_ready(adapter))
-			continue;
-
 		array[i] = (char *) adapter_get_path(adapter);
 		i++;
 	}
@@ -231,9 +228,6 @@
 	for (i = 0, list = adapters; list; list = list->next) {
 		struct btd_adapter *adapter = list->data;
 
-		if (!adapter_is_ready(adapter))
-			continue;
-
 		array[i] = (char *) adapter_get_path(adapter);
 		i++;
 	}
@@ -245,6 +239,26 @@
 	g_free(array);
 }
 
+static void manager_set_default_adapter(int id)
+{
+	struct btd_adapter *adapter;
+	const gchar *path;
+
+	default_adapter_id = id;
+
+	adapter = manager_find_adapter_by_id(id);
+	if (!adapter)
+		return;
+
+	path = adapter_get_path(adapter);
+
+	g_dbus_emit_signal(connection, "/",
+			MANAGER_INTERFACE,
+			"DefaultAdapterChanged",
+			DBUS_TYPE_OBJECT_PATH, &path,
+			DBUS_TYPE_INVALID);
+}
+
 static void manager_remove_adapter(struct btd_adapter *adapter)
 {
 	uint16_t dev_id = adapter_get_dev_id(adapter);
@@ -383,26 +397,48 @@
 	btd_stop_exit_timer();
 }
 
-int manager_register_adapter(int id, gboolean devup)
+struct btd_adapter *btd_manager_register_adapter(int id)
 {
 	struct btd_adapter *adapter;
+	const char *path;
 
 	adapter = manager_find_adapter_by_id(id);
 	if (adapter) {
 		error("Unable to register adapter: hci%d already exist", id);
-		return -1;
+		return NULL;
 	}
 
-	adapter = adapter_create(connection, id, devup);
+	adapter = adapter_create(connection, id);
 	if (!adapter)
-		return -1;
+		return NULL;
 
 	adapters = g_slist_append(adapters, adapter);
 
-	return 0;
+	if (!adapter_init(adapter)) {
+		btd_adapter_unref(adapter);
+		return NULL;
+	}
+
+
+	path = adapter_get_path(adapter);
+	g_dbus_emit_signal(connection, "/",
+				MANAGER_INTERFACE, "AdapterAdded",
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID);
+
+	manager_update_adapters();
+
+	btd_stop_exit_timer();
+
+	if (default_adapter_id < 0)
+		manager_set_default_adapter(id);
+
+	DBG("Adapter %s registered", path);
+
+	return btd_adapter_ref(adapter);
 }
 
-int manager_unregister_adapter(int id)
+int btd_manager_unregister_adapter(int id)
 {
 	struct btd_adapter *adapter;
 	const gchar *path;
@@ -420,27 +456,6 @@
 	return 0;
 }
 
-int manager_start_adapter(int id)
-{
-	struct btd_adapter *adapter;
-	int ret;
-
-	adapter = manager_find_adapter_by_id(id);
-	if (!adapter) {
-		error("Getting device data failed: hci%d", id);
-		return -EINVAL;
-	}
-
-	ret = adapter_start(adapter);
-	if (ret < 0)
-		return ret;
-
-	if (default_adapter_id < 0)
-		manager_set_default_adapter(id);
-
-	return ret;
-}
-
 int manager_stop_adapter(int id)
 {
 	struct btd_adapter *adapter;
@@ -451,7 +466,7 @@
 		return -EINVAL;
 	}
 
-	return adapter_stop(adapter);
+	return btd_adapter_stop(adapter);
 }
 
 int manager_get_default_adapter()
@@ -459,26 +474,6 @@
 	return default_adapter_id;
 }
 
-void manager_set_default_adapter(int id)
-{
-	struct btd_adapter *adapter;
-	const gchar *path;
-
-	default_adapter_id = id;
-
-	adapter = manager_find_adapter_by_id(id);
-	if (!adapter)
-		return;
-
-	path = adapter_get_path(adapter);
-
-	g_dbus_emit_signal(connection, "/",
-			MANAGER_INTERFACE,
-			"DefaultAdapterChanged",
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_INVALID);
-}
-
 void btd_manager_set_offline(gboolean offline)
 {
 	GSList *l;
diff --git a/src/manager.h b/src/manager.h
index e6d5dd9..504df22 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -36,13 +36,11 @@
 struct btd_adapter *manager_find_adapter_by_path(const char *path);
 struct btd_adapter *manager_find_adapter_by_id(int id);
 GSList *manager_get_adapters(void);
-int manager_register_adapter(int id, gboolean devup);
-int manager_unregister_adapter(int id);
-int manager_start_adapter(int id);
+struct btd_adapter *btd_manager_register_adapter(int id);
+int btd_manager_unregister_adapter(int id);
 int manager_stop_adapter(int id);
 void manager_add_adapter(const char *path);
 int manager_get_default_adapter();
-void manager_set_default_adapter(int id);
 void manager_update_svc(struct btd_adapter *adapter, uint8_t svc);
 void btd_manager_set_offline(gboolean offline);
 void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version);