Index: uspace/drv/bus/usb/usbhub/port.c
===================================================================
--- uspace/drv/bus/usb/usbhub/port.c	(revision c4f7bf6d66e1017c52094600930917ad0597d044)
+++ uspace/drv/bus/usb/usbhub/port.c	(revision b300d2b8e7f88ba124a090065b5fd3fa47a84b81)
@@ -41,5 +41,4 @@
 
 #include <usb/debug.h>
-#include <usb/dev/hub.h>
 
 #include "port.h"
@@ -58,5 +57,4 @@
     usb_port_status_t status);
 static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
-static int enable_port_callback(void *arg);
 static int add_device_phase1_worker_fibril(void *arg);
 static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
@@ -66,5 +64,5 @@
 {
 	assert(port);
-	if (port->attached_device.fun)
+	if (port->device_attached)
 		return usb_hub_port_device_gone(port, hub);
 	return EOK;
@@ -141,10 +139,10 @@
 	assert(port);
 	assert(hub);
-	usb_log_debug("Interrupt at port %zu\n", port->port_number);
+	usb_log_debug("Interrupt at port %u\n", port->port_number);
 
 	usb_port_status_t status = 0;
 	const int opResult = get_port_status(port, &status);
 	if (opResult != EOK) {
-		usb_log_error("Failed to get port %zu status: %s.\n",
+		usb_log_error("Failed to get port %u status: %s.\n",
 		    port->port_number, str_error(opResult));
 		return;
@@ -155,5 +153,5 @@
 		const bool connected =
 		    (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
-		usb_log_debug("Connection change on port %zu: device %s.\n",
+		usb_log_debug("Connection change on port %u: device %s.\n",
 		    port->port_number, connected ? "attached" : "removed");
 
@@ -171,5 +169,5 @@
 			if (opResult != EOK) {
 				usb_log_error(
-				    "Cannot handle change on port %zu: %s.\n",
+				    "Cannot handle change on port %u: %s.\n",
 				    port->port_number, str_error(opResult));
 			}
@@ -185,5 +183,5 @@
 	/* Enable change, ports are automatically disabled on errors. */
 	if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
-		usb_log_info("Port %zu, disabled because of errors.\n",
+		usb_log_info("Port %u, disabled because of errors.\n",
 		   port->port_number);
 		usb_hub_port_device_gone(port, hub);
@@ -192,5 +190,5 @@
 		if (rc != EOK) {
 			usb_log_error(
-			    "Failed to clear port %zu enable change feature: "
+			    "Failed to clear port %u enable change feature: "
 			    "%s.\n", port->port_number, str_error(rc));
 		}
@@ -200,5 +198,5 @@
 	/* Suspend change */
 	if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
-		usb_log_error("Port %zu went to suspend state, this should"
+		usb_log_error("Port %u went to suspend state, this should"
 		    "NOT happen as we do not support suspend state!",
 		    port->port_number);
@@ -207,5 +205,5 @@
 		if (rc != EOK) {
 			usb_log_error(
-			    "Failed to clear port %zu suspend change feature: "
+			    "Failed to clear port %u suspend change feature: "
 			    "%s.\n", port->port_number, str_error(rc));
 		}
@@ -223,5 +221,5 @@
 		if (rc != EOK) {
 			usb_log_error(
-			    "Failed to clear port %zu OC change feature: %s.\n",
+			    "Failed to clear port %u OC change feature: %s.\n",
 			    port->port_number, str_error(rc));
 		}
@@ -231,5 +229,5 @@
 			if (rc != EOK) {
 				usb_log_error(
-				    "Failed to set port %zu power after OC:"
+				    "Failed to set port %u power after OC:"
 				    " %s.\n", port->port_number, str_error(rc));
 			}
@@ -242,5 +240,5 @@
 	}
 
-	usb_log_debug("Port %zu status 0x%08" PRIx32 "\n",
+	usb_log_debug("Port %u status %#08" PRIx32 "\n",
 	    port->port_number, status);
 }
@@ -259,43 +257,13 @@
 	assert(port);
 	assert(hub);
-	if (port->attached_device.address < 0) {
-		usb_log_warning(
-		    "Device on port %zu removed before being registered.\n",
-		    port->port_number);
-
-		/*
-		 * Device was removed before port reset completed.
-		 * We will announce a failed port reset to unblock the
-		 * port reset callback from new device wrapper.
-		 */
-		usb_hub_port_reset_fail(port);
-		return EOK;
-	}
-
-	fibril_mutex_lock(&port->mutex);
-	assert(port->attached_device.fun);
-	usb_log_debug("Removing device on port %zu.\n", port->port_number);
-	int ret = ddf_fun_unbind(port->attached_device.fun);
-	if (ret != EOK) {
-		usb_log_error("Failed to unbind child function on port"
-		    " %zu: %s.\n", port->port_number, str_error(ret));
-		fibril_mutex_unlock(&port->mutex);
-		return ret;
-	}
-
-	ddf_fun_destroy(port->attached_device.fun);
-	port->attached_device.fun = NULL;
-
-	ret = usb_hub_unregister_device(&hub->usb_device->hc_conn,
-	    &port->attached_device);
-	if (ret != EOK) {
-		usb_log_warning("Failed to unregister address of the "
-		    "removed device: %s.\n", str_error(ret));
-	}
-
-	port->attached_device.address = -1;
-	fibril_mutex_unlock(&port->mutex);
-	usb_log_info("Removed device on port %zu.\n", port->port_number);
-	return EOK;
+	async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
+	if (!exch)
+		return ENOMEM;
+	const int rc = usb_device_remove(exch, port->port_number);
+	usb_device_bus_exchange_end(exch);
+	if (rc == EOK)
+		port->device_attached = false;
+	return rc;
+
 }
 
@@ -318,8 +286,8 @@
 
 	if (port->reset_okay) {
-		usb_log_debug("Port %zu reset complete.\n", port->port_number);
+		usb_log_debug("Port %u reset complete.\n", port->port_number);
 	} else {
 		usb_log_warning(
-		    "Port %zu reset complete but port not enabled.\n",
+		    "Port %u reset complete but port not enabled.\n",
 		    port->port_number);
 	}
@@ -331,5 +299,5 @@
 	if (rc != EOK) {
 		usb_log_error(
-		    "Failed to clear port %zu reset change feature: %s.\n",
+		    "Failed to clear port %u reset change feature: %s.\n",
 		    port->port_number, str_error(rc));
 	}
@@ -376,34 +344,26 @@
 }
 
-/** Callback for enabling a specific port.
- *
- * We wait on a CV until port is reseted.
- * That is announced via change on interrupt pipe.
- *
- * @param port_no Port number (starting at 1).
- * @param arg Custom argument, points to @c usb_hub_dev_t.
- * @return Error code.
- */
-static int enable_port_callback(void *arg)
-{
-	usb_hub_port_t *port = arg;
-	assert(port);
-	const int rc =
-	    usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
-	if (rc != EOK) {
-		usb_log_warning("Port reset failed: %s.\n", str_error(rc));
-		return rc;
-	}
-
-	/*
-	 * Wait until reset completes.
-	 */
-	fibril_mutex_lock(&port->mutex);
-	while (!port->reset_completed) {
-		fibril_condvar_wait(&port->reset_cv, &port->mutex);
-	}
-	fibril_mutex_unlock(&port->mutex);
-
-	return port->reset_okay ? EOK : ESTALL;
+static int port_enable(usb_hub_port_t *port, bool enable)
+{
+	if (enable) {
+		const int rc =
+		    usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
+		if (rc != EOK) {
+			usb_log_error("Port reset failed: %s.\n",
+			    str_error(rc));
+		} else {
+			/* Wait until reset completes. */
+			fibril_mutex_lock(&port->mutex);
+			while (!port->reset_completed) {
+				fibril_condvar_wait(&port->reset_cv,
+				    &port->mutex);
+			}
+			fibril_mutex_unlock(&port->mutex);
+		}
+		return port->reset_okay ? EOK : ESTALL;
+	} else {
+		return usb_hub_port_clear_feature(port,
+				USB_HUB_FEATURE_PORT_ENABLE);
+	}
 }
 
@@ -418,40 +378,70 @@
 int add_device_phase1_worker_fibril(void *arg)
 {
-	struct add_device_phase1 *data = arg;
-	assert(data);
-
-	usb_address_t new_address;
-	ddf_fun_t *child_fun;
-
-	const int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
-	    &data->hub->usb_device->hc_conn, data->speed, enable_port_callback,
-	    data->port, &new_address, NULL, NULL, &child_fun);
-
-	if (rc == EOK) {
-		fibril_mutex_lock(&data->port->mutex);
-		data->port->attached_device.fun = child_fun;
-		data->port->attached_device.address = new_address;
-		fibril_mutex_unlock(&data->port->mutex);
-
-		usb_log_info("Detected new device on `%s' (port %zu), "
-		    "address %d (handle %" PRIun ").\n",
-		    ddf_dev_get_name(data->hub->usb_device->ddf_dev),
-		    data->port->port_number, new_address,
-		    ddf_fun_get_handle(child_fun));
+	struct add_device_phase1 *params = arg;
+	assert(params);
+
+	int ret = EOK;
+	usb_hub_dev_t *hub = params->hub;
+	usb_hub_port_t *port = params->port;
+	const usb_speed_t speed = params->speed;
+	free(arg);
+
+	async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
+	if (!exch) {
+		usb_log_error("Failed to begin bus exchange\n");
+		ret = ENOMEM;
+		goto out;
+	}
+
+	/* Reserve default address */
+	while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) {
+		async_usleep(1000000);
+	}
+	if (ret != EOK) {
+		usb_log_error("Failed to reserve default address: %s\n",
+		    str_error(ret));
+		goto out;
+	}
+
+	/* Reset port */
+	port_enable(port, true);
+	if (!port->reset_completed || !port->reset_okay) {
+		usb_log_error("Failed to reset port %u\n", port->port_number);
+		if (usb_release_default_address(exch) != EOK)
+			usb_log_warning("Failed to release default address\n");
+		ret = EIO;
+		goto out;
+	}
+
+	ret = usb_device_enumerate(exch, port->port_number);
+	if (ret != EOK) {
+		usb_log_error("Failed to enumerate device on port %u: %s",
+		    port->port_number, str_error(ret));
+		const int ret = port_enable(port, false);
+		if (ret != EOK) {
+			usb_log_warning("Failed to disable port %u (%s), NOT "
+			    "releasing default address.", port->port_number,
+			    str_error(ret));
+		} else {
+			const int ret = usb_release_default_address(exch);
+			if (ret != EOK)
+				usb_log_warning("Failed to release default "
+				    "address: %s", str_error(ret));
+		}
 	} else {
-		usb_log_error("Failed registering device on port %zu: %s.\n",
-		    data->port->port_number, str_error(rc));
-	}
-
-
-	fibril_mutex_lock(&data->hub->pending_ops_mutex);
-	assert(data->hub->pending_ops_count > 0);
-	--data->hub->pending_ops_count;
-	fibril_condvar_signal(&data->hub->pending_ops_cv);
-	fibril_mutex_unlock(&data->hub->pending_ops_mutex);
-
-	free(arg);
-
-	return rc;
+		port->device_attached = true;
+		if (usb_release_default_address(exch) != EOK)
+			usb_log_warning("Failed to release default address\n");
+	}
+out:
+	usb_device_bus_exchange_end(exch);
+
+	fibril_mutex_lock(&hub->pending_ops_mutex);
+	assert(hub->pending_ops_count > 0);
+	--hub->pending_ops_count;
+	fibril_condvar_signal(&hub->pending_ops_cv);
+	fibril_mutex_unlock(&hub->pending_ops_mutex);
+
+	return ret;
 }
 
