Index: uspace/drv/bus/usb/usbhub/usbhub.c
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.c	(revision 46c5dc2cfe349ac12eec256f2c57ef48f6acee61)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision 0b90f49facd0f9492b99893d5ce89620a02711c6)
@@ -89,4 +89,17 @@
     bool was_error, void *data);
 
+static bool usb_hub_polling_error_callback(usb_device_t *dev, int err_code, void *arg)
+{
+	assert(dev);
+	assert(arg);
+	usb_hub_dev_t *hub = arg;
+
+	usb_log_error("Device %s polling error: %s", usb_device_get_name(dev),
+	    str_error(err_code));
+
+	/* Continue polling until the device is about to be removed. */
+	return hub->running && !hub->poll_stop;
+}
+
 /**
  * Initialize hub device driver structure.
@@ -110,6 +123,9 @@
 	hub_dev->pending_ops_count = 0;
 	hub_dev->running = false;
+	hub_dev->poll_stop = false;
 	fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
+	fibril_mutex_initialize(&hub_dev->poll_guard);
 	fibril_condvar_initialize(&hub_dev->pending_ops_cv);
+	fibril_condvar_initialize(&hub_dev->poll_cv);
 
 	/* Set hub's first configuration. (There should be only one) */
@@ -151,5 +167,6 @@
 	    &hub_status_change_endpoint_description,
 	    hub_port_changes_callback, ((hub_dev->port_count + 1 + 7) / 8),
-	    -1, NULL, usb_hub_polling_terminated_callback, hub_dev);
+	    -1, usb_hub_polling_error_callback,
+	    usb_hub_polling_terminated_callback, hub_dev);
 	if (opResult != EOK) {
 		/* Function is already bound */
@@ -176,12 +193,58 @@
 int usb_hub_device_remove(usb_device_t *usb_dev)
 {
-	/* TODO: Implement me! */
+	assert(usb_dev);
+	usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
+	assert(hub);
+
+	usb_log_info("(%p) USB hub will be removed.", hub);
+
+	/* Instruct the hub to stop once endpoints are unregistered. */
+	hub->poll_stop = true;
 	return EOK;
 }
 
+static int usb_hub_cleanup(usb_hub_dev_t *hub)
+{
+	assert(!hub->running);
+
+	for (size_t port = 0; port < hub->port_count; ++port) {
+		const int ret = usb_hub_port_fini(&hub->ports[port], hub);
+		if (ret != EOK)
+			return ret;
+	}
+	free(hub->ports);
+
+	const int ret = ddf_fun_unbind(hub->hub_fun);
+	if (ret != EOK) {
+		usb_log_error("(%p) Failed to unbind '%s' function: %s.",
+		   hub, HUB_FNC_NAME, str_error(ret));
+		return ret;
+	}
+	ddf_fun_destroy(hub->hub_fun);
+
+	usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
+
+	/* Device data (usb_hub_dev_t) will be freed by usbdev. */
+	return EOK;
+}
+
 int usb_hub_device_removed(usb_device_t *usb_dev)
 {
-	/* TODO: Implement me! */
-	return EOK;
+	assert(usb_dev);
+	usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
+	assert(hub);
+
+	usb_log_info("(%p) USB hub was removed, joining polling fibril.", hub);
+
+	/* Join polling fibril. */
+	fibril_mutex_lock(&hub->poll_guard);
+	while (hub->running)
+		fibril_condvar_wait(&hub->poll_cv, &hub->poll_guard);
+	fibril_mutex_unlock(&hub->poll_guard);
+
+	usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
+
+	/* Destroy hub. */
+	return usb_hub_cleanup(hub);
 }
 
@@ -196,4 +259,9 @@
 	usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
 	assert(hub);
+
+	hub->poll_stop = true;
+	usb_log_info("(%p) USB hub gone, joining polling fibril.", hub);
+
+	// TODO: Join the polling fibril in a better way?
 	unsigned tries = 10;
 	while (hub->running) {
@@ -206,23 +274,5 @@
 	}
 
-	assert(!hub->running);
-
-	for (size_t port = 0; port < hub->port_count; ++port) {
-		const int ret = usb_hub_port_fini(&hub->ports[port], hub);
-		if (ret != EOK)
-			return ret;
-	}
-	free(hub->ports);
-
-	const int ret = ddf_fun_unbind(hub->hub_fun);
-	if (ret != EOK) {
-		usb_log_error("(%p) Failed to unbind '%s' function: %s.",
-		   hub, HUB_FNC_NAME, str_error(ret));
-		return ret;
-	}
-	ddf_fun_destroy(hub->hub_fun);
-
-	usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
-	return EOK;
+	return usb_hub_cleanup(hub);
 }
 
@@ -534,4 +584,9 @@
 	fibril_mutex_unlock(&hub->pending_ops_mutex);
 	hub->running = false;
+
+	/* Signal polling end to joining thread. */
+	fibril_mutex_lock(&hub->poll_guard);
+	fibril_condvar_signal(&hub->poll_cv);
+	fibril_mutex_unlock(&hub->poll_guard);
 }
 /**
Index: uspace/drv/bus/usb/usbhub/usbhub.h
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.h	(revision 46c5dc2cfe349ac12eec256f2c57ef48f6acee61)
+++ uspace/drv/bus/usb/usbhub/usbhub.h	(revision 0b90f49facd0f9492b99893d5ce89620a02711c6)
@@ -74,9 +74,13 @@
 	ddf_fun_t *hub_fun;
 	/** Status indicator */
-	bool running;
+	volatile bool running;
 	/** Hub supports port power switching. */
 	bool power_switched;
 	/** Each port is switched individually. */
 	bool per_port_power;
+	/** True if the device should stop running as soon as possible. */
+	volatile bool poll_stop;
+	fibril_mutex_t poll_guard;
+	fibril_condvar_t poll_cv;
 };
 
