Index: uspace/drv/bus/usb/xhci/commands.c
===================================================================
--- uspace/drv/bus/usb/xhci/commands.c	(revision 889146e9b7a3599240dc6e7f9960962f5c52db8c)
+++ uspace/drv/bus/usb/xhci/commands.c	(revision eb928c41f71932f3f5d29785e9599d8fa22a271d)
@@ -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)
