Index: uspace/drv/bus/usb/ehci/ehci_bus.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.c	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/ehci/ehci_bus.c	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -135,45 +135,4 @@
 }
 
-static int ehci_device_online(device_t *device)
-{
-	int err;
-
-	/* Allow creation of new endpoints and transfers. */
-	usb_log_info("Device(%d): Going online.", device->address);
-	fibril_mutex_lock(&device->guard);
-	device->online = true;
-	fibril_mutex_unlock(&device->guard);
-
-	if ((err = ddf_fun_online(device->fun))) {
-		return err;
-	}
-
-	return EOK;
-}
-
-static int ehci_device_offline(device_t *device)
-{
-	int err;
-
-	/* Tear down all drivers working with the device. */
-	if ((err = ddf_fun_offline(device->fun))) {
-		return err;
-	}
-
-	/* At this point, all drivers are assumed to have already terminated
-	 * in a consistent way. The following code just cleans up hanging
-	 * transfers if there are any. */
-
-	/* Block creation of new endpoints and transfers. */
-	usb_log_info("Device(%d): Going offline.", device->address);
-	fibril_mutex_lock(&device->guard);
-	device->online = false;
-	fibril_mutex_unlock(&device->guard);
-
-	/* FIXME: Abort all transfers to all endpoints. */
-
-	return EOK;
-}
-
 static const bus_ops_t ehci_bus_ops = {
 	.parent = &usb2_bus_ops,
@@ -190,6 +149,4 @@
 	.batch_destroy = ehci_destroy_batch,
 	.batch_schedule = ehci_hc_schedule,
-	.device_online = ehci_device_online,
-	.device_offline = ehci_device_offline,
 };
 
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -321,51 +321,16 @@
 }
 
-static int device_online(device_t *device)
-{
-	int err;
-	hc_t *instance = bus_to_hc(device->bus);
-	assert(instance);
-
-	/* Allow creation of new endpoints and transfers. */
-	usb_log_info("Device(%d): Going online.", device->address);
-	fibril_mutex_lock(&device->guard);
-	device->online = true;
-	fibril_mutex_unlock(&device->guard);
-
-	if ((err = ddf_fun_online(device->fun))) {
-		return err;
-	}
-
-	return EOK;
-}
-
-static int device_offline(device_t *device)
-{
-	int err;
-	hc_t *instance = bus_to_hc(device->bus);
-	assert(instance);
-
-	/* Tear down all drivers working with the device. */
-	if ((err = ddf_fun_offline(device->fun))) {
-		return err;
-	}
-
-	/* At this point, all drivers are assumed to have already terminated
-	 * in a consistent way. The following code just cleans up hanging
-	 * transfers if there are any. */
-
-	/* Block creation of new endpoints and transfers. */
-	usb_log_info("Device(%d): Going offline.", device->address);
-	fibril_mutex_lock(&device->guard);
-	device->online = false;
-	fibril_mutex_unlock(&device->guard);
-
-	/* Abort all transfers to all endpoints. */
-	transfer_list_abort_device(&instance->transfers_interrupt, device->address);
-	transfer_list_abort_device(&instance->transfers_control_slow, device->address);
-	transfer_list_abort_device(&instance->transfers_control_full, device->address);
-	transfer_list_abort_device(&instance->transfers_bulk_full, device->address);
-
-	return EOK;
+static void endpoint_unregister(endpoint_t *ep)
+{
+	usb2_bus_ops.endpoint_unregister(ep);
+
+	fibril_mutex_lock(&ep->guard);
+	if (ep->active_batch) {
+		uhci_transfer_batch_t *ub = uhci_transfer_batch_get(ep->active_batch);
+		uhci_transfer_batch_abort(ub);
+
+		assert(ep->active_batch == NULL);
+	}
+	fibril_mutex_unlock(&ep->guard);
 }
 
@@ -379,11 +344,10 @@
 	.status = hc_status,
 
+	.endpoint_unregister = endpoint_unregister,
 	.endpoint_count_bw = bandwidth_count_usb11,
+
 	.batch_create = create_transfer_batch,
 	.batch_schedule = hc_schedule,
 	.batch_destroy = destroy_transfer_batch,
-
-	.device_online = device_online,
-	.device_offline = device_offline,
 };
 
@@ -522,6 +486,6 @@
 static int hc_schedule(usb_transfer_batch_t *batch)
 {
+	assert(batch);
 	hc_t *instance = bus_to_hc(endpoint_get_bus(batch->ep));
-	assert(batch);
 
 	if (batch->target.address == uhci_rh_get_address(&instance->rh))
Index: uspace/drv/bus/usb/uhci/transfer_list.c
===================================================================
--- uspace/drv/bus/usb/uhci/transfer_list.c	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/uhci/transfer_list.c	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -194,32 +194,6 @@
 	while (!list_empty(&instance->batch_list)) {
 		link_t * const current = list_first(&instance->batch_list);
-		uhci_transfer_batch_t *batch =
-		    uhci_transfer_batch_from_link(current);
+		uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current);
 		transfer_list_remove_batch(instance, batch);
-		endpoint_abort(batch->base.ep);
-	}
-	fibril_mutex_unlock(&instance->guard);
-}
-
-/** Walk the list and finish all batches of a specified device with EINTR.
- *
- * @param[in] instance List to use.
- * @param[in] address Address of the specified device. Other addresses are skipped.
- */
-void transfer_list_abort_device(transfer_list_t *instance, usb_address_t address)
-{
-	fibril_mutex_lock(&instance->guard);
-	link_t *current = list_first(&instance->batch_list);
-	while (current && current != &instance->batch_list.head && !list_empty(&instance->batch_list)) {
-		link_t * const next = current->next;
-		uhci_transfer_batch_t *batch =
-		    uhci_transfer_batch_from_link(current);
-
-		if (batch->base.target.address == address) {
-			transfer_list_remove_batch(instance, batch);
-			endpoint_abort(batch->base.ep);
-		}
-
-		current = next;
 	}
 	fibril_mutex_unlock(&instance->guard);
Index: uspace/drv/bus/usb/uhci/transfer_list.h
===================================================================
--- uspace/drv/bus/usb/uhci/transfer_list.h	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/uhci/transfer_list.h	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -63,5 +63,4 @@
 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done);
 void transfer_list_abort_all(transfer_list_t *instance);
-void transfer_list_abort_device(transfer_list_t *instance, usb_address_t address);
 
 #endif
Index: uspace/drv/bus/usb/uhci/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -64,4 +64,45 @@
 }
 
+/**
+ * Abort a transfer that is currently running.
+ * Call with endpoint guard locked.
+ */
+void uhci_transfer_batch_abort(uhci_transfer_batch_t *batch)
+{
+	assert(batch);
+
+	endpoint_t *ep = batch->base.ep;
+	assert(ep);
+	assert(fibril_mutex_is_locked(&ep->guard));
+	assert(ep->active_batch == &batch->base);
+
+	/*
+	 * TODO: Do some magic here to remove the batch from schedule.
+	 */
+
+	/*
+	 * Wait for 2 frames. If the transfer was being processed,
+	 * it shall be marked as finished already after 1ms.
+	 */
+	endpoint_wait_timeout_locked(ep, 2000);
+	if (ep->active_batch != &batch->base)
+		return;
+
+	/*
+	 * Now, we can be sure the transfer is not scheduled,
+	 * and as such will not be completed. We now own the batch.
+	 */
+	endpoint_deactivate_locked(ep);
+
+	/* Leave the critical section for finishing the batch. */
+	fibril_mutex_unlock(&ep->guard);
+
+	batch->base.error = EINTR;
+	batch->base.transfered_size = 0;
+	usb_transfer_batch_finish(&batch->base);
+
+	fibril_mutex_lock(&ep->guard);
+}
+
 /** Allocate memory and initialize internal data structure.
  *
Index: uspace/drv/bus/usb/uhci/uhci_batch.h
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.h	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/uhci/uhci_batch.h	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -70,5 +70,5 @@
 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *);
 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *);
-void uhci_transfer_batch_finish(uhci_transfer_batch_t *);
+void uhci_transfer_batch_abort(uhci_transfer_batch_t *);
 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *);
 
Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision bad4a050d11dd44a634a911a7e5a42918d984aab)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 0892663adc814c89139511bb2bea33fffe20ff46)
@@ -209,28 +209,4 @@
 	xhci_device_t *xhci_dev = xhci_device_get(dev);
 
-	/* Block creation of new endpoints and transfers. */
-	usb_log_debug2("Device " XHCI_DEV_FMT " going offline.", XHCI_DEV_ARGS(*xhci_dev));
-	fibril_mutex_lock(&dev->guard);
-	dev->online = false;
-	fibril_mutex_unlock(&dev->guard);
-
-	/* Abort running transfers. */
-	usb_log_debug2("Aborting all active transfers to device " XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*xhci_dev));
-	for (usb_endpoint_t i = 0; i < USB_ENDPOINT_MAX; ++i) {
-		xhci_endpoint_t *ep = xhci_device_get_endpoint(xhci_dev, i);
-		if (!ep)
-			continue;
-
-		endpoint_abort(&ep->base);
-	}
-
-	/* TODO: Figure out how to handle errors here. So far, they are reported and skipped. */
-
-	/* Make DDF (and all drivers) forget about the device. */
-	if ((err = ddf_fun_unbind(dev->fun))) {
-		usb_log_warning("Failed to unbind DDF function of device " XHCI_DEV_FMT ": %s",
-		    XHCI_DEV_ARGS(*xhci_dev), str_error(err));
-	}
-
 	/* Disable the slot, dropping all endpoints. */
 	const uint32_t slot_id = xhci_dev->slot_id;
@@ -241,16 +217,4 @@
 
 	bus->devices_by_slot[slot_id] = NULL;
-
-	/* Unregister remaining endpoints, freeing memory. */
-	for (usb_endpoint_t i = 0; i < USB_ENDPOINT_MAX; ++i) {
-		if (!dev->endpoints[i])
-			continue;
-
-		bus_endpoint_remove(dev->endpoints[i]);
-	}
-
-	/* Destroy DDF device. */
-	/* XXX: Not a good idea, this method should not destroy devices. */
-	hcd_ddf_fun_destroy(dev);
 }
 
@@ -273,13 +237,4 @@
 	if ((err = hc_configure_device(bus->hc, dev->slot_id))) {
 		usb_log_warning("Failed to configure device " XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*dev));
-	}
-
-	/* Allow creation of new endpoints and transfers. */
-	usb_log_debug2("Device " XHCI_DEV_FMT " going online.", XHCI_DEV_ARGS(*dev));
-	fibril_mutex_lock(&dev_base->guard);
-	dev_base->online = true;
-	fibril_mutex_unlock(&dev_base->guard);
-
-	if ((err = ddf_fun_online(dev_base->fun))) {
 		return err;
 	}
@@ -294,5 +249,5 @@
  * Bus callback.
  */
-static int device_offline(device_t *dev_base)
+static void device_offline(device_t *dev_base)
 {
 	int err;
@@ -303,24 +258,4 @@
 	xhci_device_t *dev = xhci_device_get(dev_base);
 	assert(dev);
-
-	/* Tear down all drivers working with the device. */
-	if ((err = ddf_fun_offline(dev_base->fun))) {
-		return err;
-	}
-
-	/* Block creation of new endpoints and transfers. */
-	usb_log_debug2("Device " XHCI_DEV_FMT " going offline.", XHCI_DEV_ARGS(*dev));
-	fibril_mutex_lock(&dev_base->guard);
-	dev_base->online = false;
-	fibril_mutex_unlock(&dev_base->guard);
-
-	/* We will need the endpoint array later for DS deallocation. */
-	endpoint_t *endpoints[USB_ENDPOINT_MAX];
-	memcpy(endpoints, dev->base.endpoints, sizeof(endpoints));
-
-	for (usb_endpoint_t i = 1; i < USB_ENDPOINT_MAX; ++i) {
-		/* FIXME: Asserting here that the endpoint is not active. If not, EBUSY? */
-		dev->base.endpoints[i] = NULL;
-	}
 
 	/* Issue one HC command to simultaneously drop all endpoints except zero. */
@@ -329,15 +264,4 @@
 		    XHCI_DEV_ARGS(*dev));
 	}
-
-	/* Tear down TRB ring / PSA. */
-	for (unsigned i = 1; i < ARRAY_SIZE(endpoints); ++i) {
-		if (!endpoints[i])
-			continue;
-
-		/* Bus reference */
-		endpoint_del_ref(endpoints[i]);
-	}
-
-	return EOK;
 }
 
@@ -378,35 +302,9 @@
 
 /**
- * Register an andpoint to the bus. Allocate its transfer ring(s) and inform
- * xHC about it.
+ * Register an andpoint to the xHC.
  *
  * Bus callback.
  */
 static int endpoint_register(endpoint_t *ep_base)
-{
-	int err;
-	xhci_bus_t *bus = bus_to_xhci_bus(endpoint_get_bus(ep_base));
-	xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
-
-	xhci_device_t *dev = xhci_device_get(ep_base->device);
-
-	usb_log_info("Endpoint " XHCI_EP_FMT " registered to XHCI bus.", XHCI_EP_ARGS(*ep));
-
-	xhci_ep_ctx_t ep_ctx;
-	xhci_setup_endpoint_context(ep, &ep_ctx);
-
-	if ((err = hc_add_endpoint(bus->hc, dev->slot_id, xhci_endpoint_index(ep), &ep_ctx)))
-		return err;
-
-	return EOK;
-}
-
-/**
- * Unregister an endpoint. If the device is still available, inform the xHC
- * about it. Destroy resources allocated when registering.
- *
- * Bus callback.
- */
-static void endpoint_unregister(endpoint_t *ep_base)
 {
 	int err;
@@ -415,5 +313,25 @@
 	xhci_device_t *dev = xhci_device_get(ep_base->device);
 
-	usb_log_info("Endpoint " XHCI_EP_FMT " unregistered from XHCI bus.", XHCI_EP_ARGS(*ep));
+	xhci_ep_ctx_t ep_ctx;
+	xhci_setup_endpoint_context(ep, &ep_ctx);
+
+	if ((err = hc_add_endpoint(bus->hc, dev->slot_id, xhci_endpoint_index(ep), &ep_ctx)))
+		return err;
+
+	return EOK;
+}
+
+/**
+ * Unregister an endpoint. If the device is still available, inform the xHC
+ * about it.
+ *
+ * Bus callback.
+ */
+static void endpoint_unregister(endpoint_t *ep_base)
+{
+	int err;
+	xhci_bus_t *bus = bus_to_xhci_bus(endpoint_get_bus(ep_base));
+	xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
+	xhci_device_t *dev = xhci_device_get(ep_base->device);
 
 	/* If device slot is still available, drop the endpoint. */
