Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -57,8 +57,17 @@
 static endpoint_t *endpoint_create(device_t *, const usb_endpoint_descriptors_t *);
 
-/** Assign address and control endpoint to a new XHCI device.
+/** Ops receive generic bus_t pointer. */
+static inline xhci_bus_t *bus_to_xhci_bus(bus_t *bus_base)
+{
+	assert(bus_base);
+	return (xhci_bus_t *) bus_base;
+}
+
+/**
+ * Assign address and control endpoint to a new XHCI device. Once this function
+ * successfully returns, the device is online.
+ *
  * @param[in] bus XHCI bus, in which the address is assigned.
- * @param[in] dev New device to address and configure.
- *
+ * @param[in] dev New device to address and configure./e
  * @return Error code.
  */
@@ -103,8 +112,9 @@
 }
 
-/** Retrieve and set maximum packet size for endpoint zero of a XHCI device.
+/**
+ * Retrieve and set maximum packet size for endpoint zero of a XHCI device.
+ *
  * @param[in] hc Host controller, which manages the device.
  * @param[in] dev Device with operational endpoint zero.
- *
  * @return Error code.
  */
@@ -134,6 +144,8 @@
 }
 
-/** Respond to a new device on the XHCI bus. Address it, negotiate packet size
+/**
+ * Respond to a new device on the XHCI bus. Address it, negotiate packet size
  * and retrieve USB descriptors.
+ *
  * @param[in] bus XHCI bus, where the new device emerged.
  * @param[in] dev XHCI device, which has appeared on the bus.
@@ -141,7 +153,8 @@
  * @return Error code.
  */
-int xhci_bus_enumerate_device(xhci_bus_t *bus, device_t *dev)
-{
-	int err;
+static int device_enumerate(device_t *dev)
+{
+	int err;
+	xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
 	xhci_device_t *xhci_dev = xhci_device_get(dev);
 
@@ -192,14 +205,18 @@
 static int endpoint_unregister(endpoint_t *);
 
-/** Remove device from XHCI bus. Transition it to the offline state, abort all
+/**
+ * Remove device from XHCI bus. Transition it to the offline state, abort all
  * ongoing transfers and unregister all of its endpoints.
+ *
+ * Bus callback.
+ *
  * @param[in] bus XHCI bus, from which the device is removed.
  * @param[in] dev XHCI device, which is removed from the bus.
- *
  * @return Error code.
  */
-int xhci_bus_remove_device(xhci_bus_t *bus, device_t *dev)
-{
-	int err;
+static int device_remove(device_t *dev)
+{
+	int err;
+	xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
 	xhci_device_t *xhci_dev = xhci_device_get(dev);
 
@@ -255,25 +272,9 @@
 }
 
-/** Ops receive generic bus_t pointer. */
-static inline xhci_bus_t *bus_to_xhci_bus(bus_t *bus_base)
-{
-	assert(bus_base);
-	return (xhci_bus_t *) bus_base;
-}
-
-// TODO: Fill in docstrings for XHCI bus callbacks once generic bus callbacks get their docstrings.
-
-static int device_enumerate(device_t *dev)
-{
-	xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
-	return xhci_bus_enumerate_device(bus, dev);
-}
-
-static int device_remove(device_t *dev)
-{
-	xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
-	return xhci_bus_remove_device(bus, dev);
-}
-
+/**
+ * Reverts things device_offline did, getting the device back up.
+ *
+ * Bus callback.
+ */
 static int device_online(device_t *dev_base)
 {
@@ -304,4 +305,10 @@
 }
 
+/**
+ * Make given device offline. Offline the DDF function, tear down all
+ * endpoints, issue Deconfigure Device command to xHC.
+ *
+ * Bus callback.
+ */
 static int device_offline(device_t *dev_base)
 {
@@ -353,4 +360,9 @@
 }
 
+/**
+ * Create a new xHCI endpoint structure.
+ *
+ * Bus callback.
+ */
 static endpoint_t *endpoint_create(device_t *dev, const usb_endpoint_descriptors_t *desc)
 {
@@ -367,4 +379,9 @@
 }
 
+/**
+ * Destroy given xHCI endpoint structure.
+ *
+ * Bus callback.
+ */
 static void endpoint_destroy(endpoint_t *ep)
 {
@@ -375,4 +392,10 @@
 }
 
+/**
+ * Register an andpoint to the bus. Allocate its transfer ring(s) and inform
+ * xHC about it.
+ *
+ * Bus callback.
+ */
 static int endpoint_register(endpoint_t *ep_base)
 {
@@ -401,4 +424,10 @@
 }
 
+/**
+ * Unregister an endpoint. If the device is still available, inform the xHC
+ * about it. Destroy resources allocated when registering.
+ *
+ * Bus callback.
+ */
 static int endpoint_unregister(endpoint_t *ep_base)
 {
@@ -426,36 +455,39 @@
 }
 
-static usb_transfer_batch_t *batch_create(endpoint_t *ep)
-{
-	xhci_transfer_t *transfer = xhci_transfer_create(ep);
-	return &transfer->batch;
-}
-
-static void batch_destroy(usb_transfer_batch_t *batch)
-{
-	xhci_transfer_destroy(xhci_transfer_from_batch(batch));
-}
-
-/** Structure binding XHCI static callbacks to generic bus callbacks. */
+/**
+ * Schedule a batch for xHC.
+ *
+ * Bus callback.
+ */
+static int batch_schedule(usb_transfer_batch_t *batch)
+{
+	assert(batch);
+	xhci_hc_t *hc = bus_to_hc(endpoint_get_bus(batch->ep));
+
+	if (!batch->target.address) {
+		usb_log_error("Attempted to schedule transfer to address 0.");
+		return EINVAL;
+	}
+
+	return xhci_transfer_schedule(hc, batch);
+}
+
 static const bus_ops_t xhci_bus_ops = {
-// TODO: Is it good idea to use this macro? It blurrs the fact that the callbacks and static functions are called the same.
-#define BIND_OP(op) .op = op,
-	BIND_OP(device_enumerate)
-	BIND_OP(device_remove)
-	BIND_OP(device_online)
-	BIND_OP(device_offline)
-
-	BIND_OP(endpoint_create)
-	BIND_OP(endpoint_destroy)
-	BIND_OP(endpoint_register)
-	BIND_OP(endpoint_unregister)
-
-	BIND_OP(batch_create)
-	BIND_OP(batch_destroy)
-#undef BIND_OP
-
 	.interrupt = hc_interrupt,
 	.status = hc_status,
-	.batch_schedule = hc_schedule,
+
+	.device_enumerate = device_enumerate,
+	.device_remove = device_remove,
+	.device_online = device_online,
+	.device_offline = device_offline,
+
+	.endpoint_create = endpoint_create,
+	.endpoint_destroy = endpoint_destroy,
+	.endpoint_register = endpoint_register,
+	.endpoint_unregister = endpoint_unregister,
+
+	.batch_schedule = batch_schedule,
+	.batch_create = xhci_transfer_create,
+	.batch_destroy = xhci_transfer_destroy,
 };
 
@@ -486,6 +518,6 @@
 void xhci_bus_fini(xhci_bus_t *bus)
 {
-	// FIXME: Deallocate bus->devices_by_slot?
-	// FIXME: Should there be some bus_fini() to call?
+	// FIXME: Ensure there are no more devices?
+	free(bus->devices_by_slot);
 	// FIXME: Something else we forgot?
 }
Index: uspace/drv/bus/usb/xhci/commands.c
===================================================================
--- uspace/drv/bus/usb/xhci/commands.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/commands.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -70,4 +70,10 @@
 }
 
+/**
+ * Initialize the command subsystem. Allocates the comand ring.
+ *
+ * Does not configure the CR pointer to the hardware, because the xHC will be
+ * reset before starting.
+ */
 int xhci_init_commands(xhci_hc_t *hc)
 {
@@ -89,10 +95,23 @@
 }
 
+/**
+ * Finish the command subsystem. Stops the hardware from running commands, then
+ * deallocates the ring.
+ */
 void xhci_fini_commands(xhci_hc_t *hc)
 {
+	assert(hc);
 	xhci_stop_command_ring(hc);
-	assert(hc);
-}
-
+
+	xhci_cmd_ring_t *cr = get_cmd_ring(hc);
+
+	fibril_mutex_lock(&cr->guard);
+	xhci_trb_ring_fini(&cr->trb_ring);
+	fibril_mutex_unlock(&cr->guard);
+}
+
+/**
+ * Initialize a command structure for the given command.
+ */
 void xhci_cmd_init(xhci_cmd_t *cmd, xhci_cmd_type_t type)
 {
@@ -107,4 +126,9 @@
 }
 
+/**
+ * Finish the command structure. Some command invocation includes allocating
+ * a context structure. To have the convenience in calling commands, this
+ * method deallocates all resources.
+ */
 void xhci_cmd_fini(xhci_cmd_t *cmd)
 {
@@ -119,5 +143,9 @@
 }
 
-/** Call with guard locked. */
+/**
+ * Find a command issued by TRB at @c phys inside the command list.
+ *
+ * Call with guard locked only.
+ */
 static inline xhci_cmd_t *find_command(xhci_hc_t *hc, uint64_t phys)
 {
@@ -140,5 +168,9 @@
 }
 
-static inline int enqueue_command(xhci_hc_t *hc, xhci_cmd_t *cmd, unsigned doorbell, unsigned target)
+/**
+ * Enqueue a command on the TRB ring. Ring the doorbell to initiate processing.
+ * Register the command as waiting for completion inside the command list.
+ */
+static inline int enqueue_command(xhci_hc_t *hc, xhci_cmd_t *cmd)
 {
 	xhci_cmd_ring_t *cr = get_cmd_ring(hc);
@@ -168,4 +200,8 @@
 }
 
+/**
+ * Stop the command ring. Stop processing commands, block issuing new ones.
+ * Wait until hardware acknowledges it is stopped.
+ */
 void xhci_stop_command_ring(xhci_hc_t *hc)
 {
@@ -187,4 +223,8 @@
 }
 
+/**
+ * Abort currently processed command. Note that it is only aborted when the
+ * command is "blocking" - see section 4.6.1.2 of xHCI spec.
+ */
 static void abort_command_ring(xhci_hc_t *hc)
 {
@@ -236,4 +276,7 @@
 };
 
+/**
+ * Report an error according to command completion code.
+ */
 static void report_error(int code)
 {
@@ -244,4 +287,9 @@
 }
 
+/**
+ * Handle a command completion. Feed the fibril waiting for result.
+ *
+ * @param trb The COMMAND_COMPLETION TRB found in event ring.
+ */
 int xhci_handle_command_completion(xhci_hc_t *hc, xhci_trb_t *trb)
 {
@@ -343,5 +391,5 @@
 	TRB_SET_TYPE(cmd->_header.trb, XHCI_TRB_TYPE_NO_OP_CMD);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -355,5 +403,5 @@
 	cmd->_header.trb.control |= host2xhci(32, XHCI_REG_RD(hc->xecp, XHCI_EC_SP_SLOT_TYPE) << 16);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -368,5 +416,5 @@
 	TRB_SET_SLOT(cmd->_header.trb, cmd->slot_id);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -398,5 +446,5 @@
 	TRB_SET_SLOT(cmd->_header.trb, cmd->slot_id);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -419,5 +467,5 @@
 	TRB_SET_DC(cmd->_header.trb, cmd->deconfigure);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -441,5 +489,5 @@
 	TRB_SET_SLOT(cmd->_header.trb, cmd->slot_id);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -460,5 +508,5 @@
 	TRB_SET_SLOT(cmd->_header.trb, cmd->slot_id);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -475,5 +523,5 @@
 	TRB_SET_SLOT(cmd->_header.trb, cmd->slot_id);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -495,5 +543,5 @@
 	 */
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -508,5 +556,5 @@
 	TRB_SET_SLOT(cmd->_header.trb, cmd->slot_id);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -524,5 +572,5 @@
 	TRB_SET_DEV_SPEED(cmd->_header.trb, cmd->device_speed);
 
-	return enqueue_command(hc, cmd, 0, 0);
+	return enqueue_command(hc, cmd);
 }
 
@@ -541,17 +589,24 @@
 	[XHCI_CMD_SET_TR_DEQUEUE_POINTER] = set_tr_dequeue_pointer_cmd,
 	[XHCI_CMD_RESET_DEVICE] = reset_device_cmd,
-	// TODO: Force event (optional normative, for VMM, section 4.6.12).
 	[XHCI_CMD_FORCE_EVENT] = NULL,
-	// TODO: Negotiate bandwidth (optional normative, section 4.6.13).
 	[XHCI_CMD_NEGOTIATE_BANDWIDTH] = NULL,
-	// TODO: Set latency tolerance value (optional normative, section 4.6.14).
 	[XHCI_CMD_SET_LATENCY_TOLERANCE_VALUE] = NULL,
-	// TODO: Get port bandwidth (mandatory, but needs root hub implementation, section 4.6.15).
 	[XHCI_CMD_GET_PORT_BANDWIDTH] = get_port_bandwidth_cmd,
-	// TODO: Force header (mandatory, but needs root hub implementation, section 4.6.16).
 	[XHCI_CMD_FORCE_HEADER] = NULL,
 	[XHCI_CMD_NO_OP] = no_op_cmd
 };
 
+/**
+ * Try to abort currently processed command. This is tricky, because
+ * calling fibril is not necessarily the one which issued the blocked command.
+ * Also, the trickiness intensifies by the fact that stopping a CR is denoted by
+ * event, which is again handled in different fibril. but, once we go to sleep
+ * on waiting for that event, another fibril may wake up and try to abort the
+ * blocked command.
+ *
+ * So, we mark the command ring as being restarted, wait for it to stop, and
+ * then start it again. If there was a blocked command, it will be satisfied by
+ * COMMAND_ABORTED event.
+ */
 static int try_abort_current_command(xhci_hc_t *hc)
 {
@@ -603,4 +658,13 @@
 }
 
+/**
+ * Wait, until the command is completed. The completion is triggered by
+ * COMMAND_COMPLETION event. As we do not want to rely on HW completing the
+ * command in timely manner, we timeout. Note that we can't just return an
+ * error after the timeout pass - it may be other command blocking the ring,
+ * and ours can be completed afterwards. Therefore, it is not guaranteed that
+ * this function will return in XHCI_COMMAND_TIMEOUT. It will continue waiting
+ * until COMMAND_COMPLETION event arrives.
+ */
 static int wait_for_cmd_completion(xhci_hc_t *hc, xhci_cmd_t *cmd)
 {
@@ -630,6 +694,7 @@
 }
 
-/** Issue command and block the current fibril until it is completed or timeout
- *  expires. Nothing is deallocated. Caller should always execute `xhci_cmd_fini`.
+/**
+ * Issue command and block the current fibril until it is completed or timeout
+ * expires. Nothing is deallocated. Caller should always execute `xhci_cmd_fini`.
  */
 int xhci_cmd_sync(xhci_hc_t *hc, xhci_cmd_t *cmd)
@@ -658,6 +723,7 @@
 }
 
-/** Does the same thing as `xhci_cmd_sync` and executes `xhci_cmd_fini`. This
- *  is a useful shorthand for issuing commands without out parameters.
+/**
+ * Does the same thing as `xhci_cmd_sync` and executes `xhci_cmd_fini`. This
+ * is a useful shorthand for issuing commands without out parameters.
  */
 int xhci_cmd_sync_fini(xhci_hc_t *hc, xhci_cmd_t *cmd)
@@ -669,6 +735,7 @@
 }
 
-/** Does the same thing as `xhci_cmd_sync_fini` without blocking the current
- *  fibril. The command is copied to stack memory and `fini` is called upon its completion.
+/**
+ * Does the same thing as `xhci_cmd_sync_fini` without blocking the current
+ * fibril. The command is copied to stack memory and `fini` is called upon its completion.
  */
 int xhci_cmd_async_fini(xhci_hc_t *hc, xhci_cmd_t *stack_cmd)
Index: uspace/drv/bus/usb/xhci/debug.c
===================================================================
--- uspace/drv/bus/usb/xhci/debug.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/debug.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -31,5 +31,5 @@
  */
 /** @file
- * Memory-mapped register structures of the xHC.
+ * Various functions to examine current state of the xHC.
  */
 
@@ -100,4 +100,7 @@
 }
 
+/**
+ * Dumps registers of one port.
+ */
 void xhci_dump_port(const xhci_port_regs_t *port)
 {
@@ -126,4 +129,7 @@
 }
 
+/**
+ * Dumps all registers that define state of the HC.
+ */
 void xhci_dump_state(const xhci_hc_t *hc)
 {
@@ -173,4 +179,7 @@
 }
 
+/**
+ * Dump registers of all ports.
+ */
 void xhci_dump_ports(const xhci_hc_t *hc)
 {
@@ -221,4 +230,7 @@
 };
 
+/**
+ * Stringify XHCI_TRB_TYPE_*.
+ */
 const char *xhci_trb_str_type(unsigned type)
 {
@@ -232,4 +244,7 @@
 }
 
+/**
+ * Dump a TRB.
+ */
 void xhci_dump_trb(const xhci_trb_t *trb)
 {
@@ -252,4 +267,7 @@
 };
 
+/**
+ * Dump Extended Capability ID.
+ */
 const char *xhci_ec_str_id(unsigned id)
 {
@@ -263,4 +281,7 @@
 }
 
+/**
+ * Dump Protocol Speed ID.
+ */
 static void xhci_dump_psi(const xhci_psi_t *psi)
 {
@@ -276,4 +297,7 @@
 }
 
+/**
+ * Dump given Extended Capability.
+ */
 void xhci_dump_extcap(const xhci_extcap_t *ec)
 {
Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -45,5 +45,6 @@
 #include "endpoint.h"
 
-/** Initialize new XHCI endpoint.
+/**
+ * Initialize new XHCI endpoint.
  * @param[in] xhci_ep Allocated XHCI endpoint to initialize.
  * @param[in] dev Device, to which the endpoint belongs.
@@ -98,5 +99,6 @@
 }
 
-/** Finalize XHCI endpoint.
+/**
+ * Finalize XHCI endpoint.
  * @param[in] xhci_ep XHCI endpoint to finalize.
  */
@@ -108,5 +110,6 @@
 }
 
-/** Determine the type of a XHCI endpoint.
+/**
+ * Determine the type of a XHCI endpoint.
  * @param[in] ep XHCI endpoint to query.
  *
@@ -137,5 +140,6 @@
 }
 
-/** Test whether an XHCI endpoint uses streams.
+/**
+ * Test whether an XHCI endpoint uses streams.
  * @param[in] xhci_ep XHCI endpoint to query.
  *
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -66,4 +66,7 @@
 /**
  * Walk the list of extended capabilities.
+ *
+ * The most interesting thing hidden in extended capabilities is the mapping of
+ * ports to protocol versions and speeds.
  */
 static int hc_parse_ec(xhci_hc_t *hc)
@@ -145,4 +148,7 @@
 }
 
+/**
+ * Initialize MMIO spaces of xHC.
+ */
 int hc_init_mmio(xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
 {
@@ -195,4 +201,7 @@
 }
 
+/**
+ * Initialize structures kept in allocated memory.
+ */
 int hc_init_memory(xhci_hc_t *hc, ddf_dev_t *device)
 {
@@ -338,4 +347,7 @@
 }
 
+/**
+ * Claim xHC from BIOS. Implements handoff as per Section 4.22.1 of xHCI spec.
+ */
 int hc_claim(xhci_hc_t *hc, ddf_dev_t *dev)
 {
@@ -344,5 +356,4 @@
 		return EOK;
 
-	/* Section 4.22.1 */
 	/* TODO: Test this with USB3-aware BIOS */
 	usb_log_debug2("LEGSUP: bios: %x, os: %x", hc->legsup->sem_bios, hc->legsup->sem_os);
@@ -363,4 +374,7 @@
 }
 
+/**
+ * Ask the xHC to reset its state. Implements sequence 
+ */
 static int hc_reset(xhci_hc_t *hc)
 {
@@ -454,17 +468,4 @@
 }
 
-int hc_schedule(usb_transfer_batch_t *batch)
-{
-	assert(batch);
-	xhci_hc_t *hc = bus_to_hc(endpoint_get_bus(batch->ep));
-
-	if (!batch->target.address) {
-		usb_log_error("Attempted to schedule transfer to address 0.");
-		return EINVAL;
-	}
-
-	return xhci_transfer_schedule(hc, batch);
-}
-
 typedef int (*event_handler) (xhci_hc_t *, xhci_trb_t *trb);
 
@@ -484,4 +485,14 @@
 }
 
+/**
+ * Dequeue from event ring and handle dequeued events.
+ *
+ * As there can be events, that blocks on waiting for subsequent events,
+ * we solve this problem by first copying the event TRBs from the event ring,
+ * then asserting EHB and only after, handling the events.
+ *
+ * Whenever the event handling blocks, it switches fibril, and incoming
+ * IPC notification will create new event handling fibril for us.
+ */
 static void hc_run_event_ring(xhci_hc_t *hc, xhci_event_ring_t *event_ring, xhci_interrupter_regs_t *intr)
 {
@@ -541,4 +552,13 @@
 }
 
+/**
+ * Handle an interrupt request from xHC. Resolve all situations that trigger an
+ * interrupt separately.
+ *
+ * Note that all RW1C bits in USBSTS register are cleared at the time of
+ * handling the interrupt in irq_code. This method is the top-half.
+ *
+ * @param status contents of USBSTS register at the time of the interrupt.
+ */
 void hc_interrupt(bus_t *bus, uint32_t status)
 {
@@ -573,4 +593,7 @@
 }
 
+/**
+ * Tear down all in-memory structures.
+ */
 void hc_fini(xhci_hc_t *hc)
 {
@@ -585,4 +608,7 @@
 }
 
+/**
+ * Ring a xHC Doorbell. Implements section 4.7.
+ */
 int hc_ring_doorbell(xhci_hc_t *hc, unsigned doorbell, unsigned target)
 {
@@ -594,4 +620,9 @@
 }
 
+/**
+ * Issue an Enable Slot command, returning the obtained Slot ID.
+ *
+ * @param slot_id Pointer where to store the obtained Slot ID.
+ */
 int hc_enable_slot(xhci_hc_t *hc, uint32_t *slot_id)
 {
@@ -615,4 +646,9 @@
 }
 
+/**
+ * Issue a Disable Slot command for a slot occupied by device.
+ *
+ * Frees the device context 
+ */
 int hc_disable_slot(xhci_hc_t *hc, xhci_device_t *dev)
 {
@@ -634,4 +670,7 @@
 }
 
+/**
+ * Prepare an empty Endpoint Input Context inside a dma buffer.
+ */
 static int create_configure_ep_input_ctx(dma_buffer_t *dma_buf)
 {
@@ -649,4 +688,10 @@
 }
 
+/**
+ * Initialize a device, assigning it an address. Implements section 4.3.4.
+ *
+ * @param dev Device to assing an address (unconfigured yet)
+ * @param ep0 EP0 of device TODO remove, can be fetched from dev
+ */
 int hc_address_device(xhci_hc_t *hc, xhci_device_t *dev, xhci_endpoint_t *ep0)
 {
@@ -713,4 +758,9 @@
 }
 
+/**
+ * Issue a Configure Device command for a device in slot.
+ *
+ * @param slot_id Slot ID assigned to the device.
+ */
 int hc_configure_device(xhci_hc_t *hc, uint32_t slot_id)
 {
@@ -726,4 +776,9 @@
 }
 
+/**
+ * Issue a Deconfigure Device command for a device in slot.
+ *
+ * @param slot_id Slot ID assigned to the device.
+ */
 int hc_deconfigure_device(xhci_hc_t *hc, uint32_t slot_id)
 {
@@ -732,4 +787,11 @@
 }
 
+/**
+ * Instruct xHC to add an endpoint with supplied endpoint context.
+ *
+ * @param slot_id Slot ID assigned to the device.
+ * @param ep_idx Endpoint index (number + direction) in question
+ * @param ep_ctx Endpoint context of the endpoint
+ */
 int hc_add_endpoint(xhci_hc_t *hc, uint32_t slot_id, uint8_t ep_idx, xhci_ep_ctx_t *ep_ctx)
 {
@@ -748,4 +810,10 @@
 }
 
+/**
+ * Instruct xHC to drop an endpoint.
+ *
+ * @param slot_id Slot ID assigned to the device.
+ * @param ep_idx Endpoint index (number + direction) in question
+ */
 int hc_drop_endpoint(xhci_hc_t *hc, uint32_t slot_id, uint8_t ep_idx)
 {
@@ -763,4 +831,12 @@
 }
 
+/**
+ * Instruct xHC to update information about an endpoint, using supplied
+ * endpoint context.
+ *
+ * @param slot_id Slot ID assigned to the device.
+ * @param ep_idx Endpoint index (number + direction) in question
+ * @param ep_ctx Endpoint context of the endpoint
+ */
 int hc_update_endpoint(xhci_hc_t *hc, uint32_t slot_id, uint8_t ep_idx, xhci_ep_ctx_t *ep_ctx)
 {
Index: uspace/drv/bus/usb/xhci/hc.h
===================================================================
--- uspace/drv/bus/usb/xhci/hc.h	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/hc.h	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -115,5 +115,4 @@
 int hc_update_endpoint(xhci_hc_t *, uint32_t, uint8_t, xhci_ep_ctx_t *);
 
-int hc_schedule(usb_transfer_batch_t *batch);
 int hc_status(bus_t *, uint32_t *);
 void hc_interrupt(bus_t *, uint32_t);
Index: uspace/drv/bus/usb/xhci/rh.c
===================================================================
--- uspace/drv/bus/usb/xhci/rh.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/rh.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -61,4 +61,7 @@
 	XHCI_REG_MASK(XHCI_PORT_CEC);
 
+/**
+ * Initialize the roothub subsystem.
+ */
 int xhci_rh_init(xhci_rh_t *rh, xhci_hc_t *hc)
 {
@@ -81,5 +84,17 @@
 }
 
-/** Create a device node for device directly connected to RH.
+/**
+ * Finalize the RH subsystem.
+ */
+int xhci_rh_fini(xhci_rh_t *rh)
+{
+	assert(rh);
+	free(rh->devices_by_port);
+	return EOK;
+}
+
+/**
+ * Create and setup a device directly connected to RH. As the xHCI is not using
+ * a virtual usbhub device for RH, this routine is called for devices directly.
  */
 static int rh_setup_device(xhci_rh_t *rh, uint8_t port_id)
@@ -89,6 +104,4 @@
 
 	assert(rh->devices_by_port[port_id - 1] == NULL);
-
-	xhci_bus_t *bus = &rh->hc->bus;
 
 	device_t *dev = hcd_ddf_fun_create(&rh->hc->base);
@@ -107,5 +120,5 @@
 	dev->speed = port_speed->usb_speed;
 
-	if ((err = xhci_bus_enumerate_device(bus, dev))) {
+	if ((err = bus_device_enumerate(dev))) {
 		usb_log_error("Failed to enumerate USB device: %s", str_error(err));
 		return err;
@@ -134,4 +147,8 @@
 }
 
+/**
+ * Handle a device connection. USB 3+ devices are set up directly, USB 2 and
+ * below first need to have their port reset.
+ */
 static int handle_connected_device(xhci_rh_t *rh, uint8_t port_id)
 {
@@ -161,14 +178,10 @@
 		usb_log_debug("USB 2 device attached, issuing reset.");
 		xhci_rh_reset_port(rh, port_id);
-		/*
-			FIXME: we need to wait for the event triggered by the reset
-			and then alloc_dev()... can't it be done directly instead of
-			going around?
-		*/
 		return EOK;
 	}
 }
 
-/** Deal with a detached device.
+/**
+ * Deal with a detached device.
  */
 static int handle_disconnected_device(xhci_rh_t *rh, uint8_t port_id)
@@ -194,5 +207,5 @@
 
 	/* Remove device from XHCI bus. */
-	if ((err = xhci_bus_remove_device(&rh->hc->bus, &dev->base))) {
+	if ((err = bus_device_remove(&dev->base))) {
 		usb_log_warning("Failed to remove device " XHCI_DEV_FMT " from XHCI bus: %s",
 		    XHCI_DEV_ARGS(*dev), str_error(err));
@@ -202,5 +215,6 @@
 }
 
-/** Handle an incoming Port Change Detected Event.
+/**
+ * Handle an incoming Port Change Detected Event.
  */
 int xhci_rh_handle_port_status_change_event(xhci_hc_t *hc, xhci_trb_t *trb)
@@ -219,4 +233,7 @@
 }
 
+/**
+ * Handle all changes on all ports.
+ */
 void xhci_rh_handle_port_change(xhci_rh_t *rh)
 {
@@ -303,33 +320,7 @@
 }
 
-static inline int get_hub_available_bandwidth(xhci_hc_t *hc, xhci_device_t* dev, uint8_t speed, xhci_port_bandwidth_ctx_t *ctx)
-{
-	int err = EOK;
-
-	// TODO: find a correct place for this function + API
-	// We need speed, because a root hub device has both USB 2 and USB 3 speeds
-	// and the command can query only one of them
-	// ctx is an out parameter as of now
-	assert(dev);
-	assert(ctx);
-
-	xhci_cmd_t cmd;
-	xhci_cmd_init(&cmd, XHCI_CMD_GET_PORT_BANDWIDTH);
-
-	if ((err = dma_buffer_alloc(&cmd.bandwidth_ctx, sizeof(xhci_port_bandwidth_ctx_t))))
-		goto end;
-
-	cmd.device_speed = speed;
-
-	if ((err = xhci_cmd_sync(hc, &cmd)))
-		goto end;
-
-	memcpy(ctx, cmd.bandwidth_ctx.virt, sizeof(xhci_port_bandwidth_ctx_t));
-
-end:
-	xhci_cmd_fini(&cmd);
-	return err;
-}
-
+/**
+ * Get a port speed for a given port id.
+ */
 const xhci_port_speed_t *xhci_rh_get_port_speed(xhci_rh_t *rh, uint8_t port)
 {
@@ -340,4 +331,7 @@
 }
 
+/**
+ * Issue a port reset for a given port.
+ */
 int xhci_rh_reset_port(xhci_rh_t* rh, uint8_t port)
 {
@@ -349,11 +343,4 @@
 }
 
-int xhci_rh_fini(xhci_rh_t *rh)
-{
-	assert(rh);
-	free(rh->devices_by_port);
-	return EOK;
-}
-
 /**
  * @}
Index: uspace/drv/bus/usb/xhci/scratchpad.c
===================================================================
--- uspace/drv/bus/usb/xhci/scratchpad.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/scratchpad.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -41,4 +41,7 @@
 #include "scratchpad.h"
 
+/**
+ * Get the number of scratchpad buffers needed.
+ */
 static inline unsigned xhci_scratchpad_count(xhci_hc_t *hc)
 {
@@ -51,4 +54,7 @@
 }
 
+/**
+ * Allocate all scratchpad buffers, and configure the xHC.
+ */
 int xhci_scratchpad_alloc(xhci_hc_t *hc)
 {
@@ -79,4 +85,7 @@
 }
 
+/**
+ * Deallocate the scratchpads and deconfigure xHC.
+ */
 void xhci_scratchpad_free(xhci_hc_t *hc)
 {
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -94,9 +94,9 @@
 
 /**
- * There can currently be only one active transfer, because
- * usb_transfer_batch_init locks the endpoint by endpoint_use.
- * Therefore, we store the only active transfer per endpoint there.
- */
-xhci_transfer_t* xhci_transfer_create(endpoint_t* ep)
+ * Create a xHCI-specific transfer batch.
+ *
+ * Bus callback.
+ */
+usb_transfer_batch_t * xhci_transfer_create(endpoint_t* ep)
 {
 	xhci_transfer_t *transfer = calloc(1, sizeof(xhci_transfer_t));
@@ -105,10 +105,13 @@
 
 	usb_transfer_batch_init(&transfer->batch, ep);
-	return transfer;
-}
-
-void xhci_transfer_destroy(xhci_transfer_t* transfer)
-{
-	assert(transfer);
+	return &transfer->batch;
+}
+
+/**
+ * Destroy a xHCI transfer.
+ */
+void xhci_transfer_destroy(usb_transfer_batch_t* batch)
+{
+	xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
 
 	dma_buffer_free(&transfer->hc_buffer);
Index: uspace/drv/bus/usb/xhci/transfers.h
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.h	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/transfers.h	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -64,8 +64,8 @@
 } xhci_isoch_transfer_t;
 
-xhci_transfer_t* xhci_transfer_create(endpoint_t *);
+usb_transfer_batch_t* xhci_transfer_create(endpoint_t *);
 int xhci_transfer_schedule(xhci_hc_t *, usb_transfer_batch_t *);
 int xhci_handle_transfer_event(xhci_hc_t *, xhci_trb_t *);
-void xhci_transfer_destroy(xhci_transfer_t *);
+void xhci_transfer_destroy(usb_transfer_batch_t *);
 
 static inline xhci_transfer_t *xhci_transfer_from_batch(usb_transfer_batch_t *batch)
Index: uspace/drv/bus/usb/xhci/trb_ring.c
===================================================================
--- uspace/drv/bus/usb/xhci/trb_ring.c	(revision ecbad17c66f206aa044e40815229a72d36e3e544)
+++ uspace/drv/bus/usb/xhci/trb_ring.c	(revision 1102eca56d6f6100e87aeb0fd1d28fa6dac503bc)
@@ -52,4 +52,7 @@
 
 
+/**
+ * Get the first TRB of a segment.
+ */
 static inline xhci_trb_t *segment_begin(trb_segment_t *segment)
 {
@@ -57,4 +60,7 @@
 }
 
+/**
+ * Get the one-past-end TRB of a segment.
+ */
 static inline xhci_trb_t *segment_end(trb_segment_t *segment)
 {
@@ -91,5 +97,4 @@
 /**
  * Initializes the ring with one segment.
- * Event when it fails, the structure needs to be finalized.
  */
 int xhci_trb_ring_init(xhci_trb_ring_t *ring)
@@ -117,9 +122,10 @@
 	fibril_mutex_initialize(&ring->guard);
 
-	usb_log_debug2("Initialized new TRB ring.");
-
-	return EOK;
-}
-
+	return EOK;
+}
+
+/**
+ * Free all segments inside the ring.
+ */
 void xhci_trb_ring_fini(xhci_trb_ring_t *ring)
 {
@@ -150,4 +156,7 @@
 }
 
+/**
+ * Get the physical address of the enqueue pointer.
+ */
 static uintptr_t trb_ring_enqueue_phys(xhci_trb_ring_t *ring)
 {
@@ -156,4 +165,7 @@
 }
 
+/**
+ * Decides whether the TRB will trigger an interrupt after being processed.
+ */
 static bool trb_generates_interrupt(xhci_trb_t *trb)
 {
@@ -163,5 +175,5 @@
 
 /**
- * Enqueue TDs composed of TRBs.
+ * Enqueue TD composed of TRBs.
  *
  * This will copy specified number of TRBs chained together into the ring. The
@@ -256,5 +268,4 @@
 /**
  * Initializes an event ring.
- * Even when it fails, the structure needs to be finalized.
  */
 int xhci_event_ring_init(xhci_event_ring_t *ring)
@@ -275,6 +286,8 @@
 	ring->dequeue_ptr = segment->phys;
 
-	if (dma_buffer_alloc(&ring->erst, PAGE_SIZE))
+	if (dma_buffer_alloc(&ring->erst, PAGE_SIZE)) {
+		xhci_event_ring_fini(ring);
 		return ENOMEM;
+	}
 	xhci_erst_entry_t *erst = ring->erst.virt;
 
@@ -301,4 +314,7 @@
 }
 
+/**
+ * Get the physical address of the dequeue pointer.
+ */
 static uintptr_t event_ring_dequeue_phys(xhci_event_ring_t *ring)
 {
