Index: uspace/lib/usb/src/hub.c
===================================================================
--- uspace/lib/usb/src/hub.c	(revision 9f9b31ad6dd7b525ca41c274a515ef607f17e03b)
+++ uspace/lib/usb/src/hub.c	(revision 1c258d122a2cbffcb8c0f6a8c54bf9ad4ca7b925)
@@ -40,4 +40,10 @@
 #include <errno.h>
 #include <assert.h>
+#include <usb/debug.h>
+
+/** How much time to wait between attempts to register endpoint 0:0.
+ * The value is based on typical value for port reset + some overhead.
+ */
+#define ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC (1000 * (10 + 2))
 
 /** Check that HC connection is alright.
@@ -53,35 +59,4 @@
 	} while (false)
 
-
-/** Tell host controller to reserve default address.
- *
- * @param connection Opened connection to host controller.
- * @param speed Speed of the device that will respond on the default address.
- * @return Error code.
- */
-int usb_hc_reserve_default_address(usb_hc_connection_t *connection,
-    usb_speed_t speed)
-{
-	CHECK_CONNECTION(connection);
-
-	return async_req_2_0(connection->hc_phone,
-	    DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS, speed);
-}
-
-/** Tell host controller to release default address.
- *
- * @param connection Opened connection to host controller.
- * @return Error code.
- */
-int usb_hc_release_default_address(usb_hc_connection_t *connection)
-{
-	CHECK_CONNECTION(connection);
-
-	return async_req_1_0(connection->hc_phone,
-	    DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
-}
-
 /** Ask host controller for free address assignment.
  *
@@ -178,6 +153,11 @@
  * error codes than those listed as return codes by this function itself).
  *
+ * The @p connection representing connection with host controller does not
+ * need to be started.
+ * This function duplicates the connection to allow simultaneous calls of
+ * this function (i.e. from different fibrils).
+ *
  * @param[in] parent Parent device (i.e. the hub device).
- * @param[in] connection Opened connection to host controller.
+ * @param[in] connection Connection to host controller.
  * @param[in] dev_speed New device speed.
  * @param[in] enable_port Function for enabling signaling through the port the
@@ -206,43 +186,40 @@
     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
 {
-	CHECK_CONNECTION(connection);
+	assert(connection != NULL);
+	// FIXME: this is awful, we are accessing directly the structure.
+	usb_hc_connection_t hc_conn = {
+		.hc_handle = connection->hc_handle,
+		.hc_phone = -1
+	};
+
+	int rc;
+
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
 
 	/*
 	 * Request new address.
 	 */
-	usb_address_t dev_addr = usb_hc_request_address(connection, dev_speed);
+	usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
 	if (dev_addr < 0) {
+		usb_hc_connection_close(&hc_conn);
 		return EADDRNOTAVAIL;
 	}
 
-	int rc;
-
-	/*
-	 * Reserve the default address.
-	 */
-	rc = usb_hc_reserve_default_address(connection, dev_speed);
-	if (rc != EOK) {
-		rc = EBUSY;
-		goto leave_release_free_address;
-	}
-
-	/*
-	 * Enable the port (i.e. allow signaling through this port).
-	 */
-	rc = enable_port(port_no, arg);
-	if (rc != EOK) {
-		goto leave_release_default_address;
-	}
-
-	/*
-	 * Change the address from default to the free one.
-	 * We need to create a new control pipe for that.
+	/*
+	 * We will not register control pipe on default address.
+	 * The registration might fail. That means that someone else already
+	 * registered that endpoint. We will simply wait and try again.
+	 * (Someone else already wants to add a new device.)
 	 */
 	usb_device_connection_t dev_conn;
 	rc = usb_device_connection_initialize_on_default_address(&dev_conn,
-	    connection);
+	    &hc_conn);
 	if (rc != EOK) {
 		rc = ENOTCONN;
-		goto leave_release_default_address;
+		goto leave_release_free_address;
 	}
 
@@ -252,54 +229,50 @@
 	if (rc != EOK) {
 		rc = ENOTCONN;
+		goto leave_release_free_address;
+	}
+
+	do {
+		rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
+		    &hc_conn);
+		if (rc != EOK) {
+			/* Do not overheat the CPU ;-). */
+			async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
+		}
+	} while (rc != EOK);
+
+	/*
+	 * Endpoint is registered. We can enable the port and change
+	 * device address.
+	 */
+	rc = enable_port(port_no, arg);
+	if (rc != EOK) {
 		goto leave_release_default_address;
 	}
 
-	/* Before sending any traffic, we need to register this
-	 * endpoint.
-	 */
-	rc = usb_pipe_register(&ctrl_pipe, 0, connection);
-	if (rc != EOK) {
-		rc = EREFUSED;
+	rc = usb_pipe_probe_default_control(&ctrl_pipe);
+	if (rc != EOK) {
+		rc = ESTALL;
 		goto leave_release_default_address;
 	}
-	rc = usb_pipe_probe_default_control(&ctrl_pipe);
-	if (rc != EOK) {
-		rc = ENOTCONN;
+
+	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
+	if (rc != EOK) {
+		rc = ESTALL;
 		goto leave_release_default_address;
 	}
 
-	rc = usb_pipe_start_session(&ctrl_pipe);
-	if (rc != EOK) {
-		rc = ENOTCONN;
-		goto leave_unregister_endpoint;
-	}
-
-	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
-	if (rc != EOK) {
-		rc = ESTALL;
-		goto leave_stop_session;
-	}
-
-	usb_pipe_end_session(&ctrl_pipe);
-
-	/*
-	 * Register the control endpoint for the new device.
-	 */
-	rc = usb_pipe_register(&ctrl_pipe, 0, connection);
-	if (rc != EOK) {
-		rc = EREFUSED;
-		goto leave_unregister_endpoint;
-	}
-
-	/*
-	 * Release the original endpoint.
-	 */
-	unregister_control_endpoint_on_default_address(connection);
-
-	/*
-	 * Once the address is changed, we can return the default address.
-	 */
-	usb_hc_release_default_address(connection);
-
+	/*
+	 * Address changed. We can release the original endpoint, thus
+	 * allowing other to access the default address.
+	 */
+	unregister_control_endpoint_on_default_address(&hc_conn);
+
+	/*
+	 * Time to register the new endpoint.
+	 */
+	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
+	if (rc != EOK) {
+		goto leave_release_free_address;
+	}
 
 	/*
@@ -316,6 +289,4 @@
 	}
 
-
-
 	/*
 	 * And now inform the host controller about the handle.
@@ -325,5 +296,5 @@
 		.handle = child_handle
 	};
-	rc = usb_hc_register_device(connection, &new_device);
+	rc = usb_hc_register_device(&hc_conn, &new_device);
 	if (rc != EOK) {
 		rc = EDESTADDRREQ;
@@ -349,16 +320,11 @@
 	 * Completely ignoring errors here.
 	 */
-
-leave_stop_session:
-	usb_pipe_end_session(&ctrl_pipe);
-
-leave_unregister_endpoint:
-	usb_pipe_unregister(&ctrl_pipe, connection);
-
 leave_release_default_address:
-	usb_hc_release_default_address(connection);
+	usb_pipe_unregister(&ctrl_pipe, &hc_conn);
 
 leave_release_free_address:
-	usb_hc_unregister_device(connection, dev_addr);
+	usb_hc_unregister_device(&hc_conn, dev_addr);
+
+	usb_hc_connection_close(&hc_conn);
 
 	return rc;
