Index: uspace/lib/usb/include/usb/devdrv.h
===================================================================
--- uspace/lib/usb/include/usb/devdrv.h	(revision 489c3e717b06bedddbc086e518d7a166c02aa28c)
+++ uspace/lib/usb/include/usb/devdrv.h	(revision 69334af9e0de23bfa9d51b1f316f9cbe8badeeda)
@@ -38,19 +38,43 @@
 #include <usb/pipes.h>
 
+/** USB device structure. */
 typedef struct {
+	/** The default control pipe. */
 	usb_endpoint_pipe_t ctrl_pipe;
+	/** Other endpoint pipes.
+	 * This is an array of other endpoint pipes in the same order as
+	 * in usb_driver_t.
+	 */
 	usb_endpoint_mapping_t *pipes;
+	/** Generic DDF device backing this one. */
 	ddf_dev_t *ddf_dev;
+	/** Custom driver data.
+	 * Do not use the entry in generic device, that is already used
+	 * by the framework.
+	 */
 	void *driver_data;
+
+	/** Connection backing the pipes.
+	 * Typically, you will not need to use this attribute at all.
+	 */
 	usb_device_connection_t wire;
 } usb_device_t;
 
+/** USB driver ops. */
 typedef struct {
+	/** Callback when new device is about to be controlled by the driver. */
 	int (*add_device)(usb_device_t *);
 } usb_driver_ops_t;
 
+/** USB driver structure. */
 typedef struct {
+	/** Driver name.
+	 * This name is copied to the generic driver name and must be exactly
+	 * the same as the directory name where the driver executable resides.
+	 */
 	const char *name;
+	/** Expected endpoints description. */
 	usb_endpoint_description_t **endpoints;
+	/** Driver ops. */
 	usb_driver_ops_t *ops;
 } usb_driver_t;
Index: uspace/lib/usb/src/devdrv.c
===================================================================
--- uspace/lib/usb/src/devdrv.c	(revision 489c3e717b06bedddbc086e518d7a166c02aa28c)
+++ uspace/lib/usb/src/devdrv.c	(revision 69334af9e0de23bfa9d51b1f316f9cbe8badeeda)
@@ -37,4 +37,5 @@
 #include <usb/debug.h>
 #include <errno.h>
+#include <str_error.h>
 #include <assert.h>
 
@@ -50,6 +51,16 @@
 static usb_driver_t *driver = NULL;
 
+
+/** Main routine of USB device driver.
+ *
+ * Under normal conditions, this function never returns.
+ *
+ * @param drv USB device driver structure.
+ * @return Task exit status.
+ */
 int usb_driver_main(usb_driver_t *drv)
 {
+	assert(drv != NULL);
+
 	/* Prepare the generic driver. */
 	generic_driver.name = drv->name;
@@ -60,4 +71,19 @@
 }
 
+/** Log out of memory error on given device.
+ *
+ * @param dev Device causing the trouble.
+ */
+static void usb_log_oom(ddf_dev_t *dev)
+{
+	usb_log_error("Out of memory when adding device `%s'.\n",
+	    dev->name);
+}
+
+/** Count number of pipes the driver expects.
+ *
+ * @param drv USB driver.
+ * @return Number of pipes (excluding default control pipe).
+ */
 static size_t count_other_pipes(usb_driver_t *drv)
 {
@@ -74,16 +100,37 @@
 }
 
+/** Initialize endpoint pipes, excluding default control one.
+ *
+ * @param drv The device driver.
+ * @param dev Device to be initialized.
+ * @return Error code.
+ */
 static int initialize_other_pipes(usb_driver_t *drv, usb_device_t *dev)
 {
+	int rc;
 	int my_interface = usb_device_get_assigned_interface(dev->ddf_dev);
 
 	size_t pipe_count = count_other_pipes(drv);
 	dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
-	assert(dev->pipes != NULL);
+	if (dev->pipes == NULL) {
+		usb_log_oom(dev->ddf_dev);
+		return ENOMEM;
+	}
 
 	size_t i;
+
+	/* Initialize to NULL first for rollback purposes. */
+	for (i = 0; i < pipe_count; i++) {
+		dev->pipes[i].pipe = NULL;
+	}
+
 	for (i = 0; i < pipe_count; i++) {
 		dev->pipes[i].pipe = malloc(sizeof(usb_endpoint_pipe_t));
-		assert(dev->pipes[i].pipe != NULL);
+		if (dev->pipes[i].pipe == NULL) {
+			usb_log_oom(dev->ddf_dev);
+			rc = ENOMEM;
+			goto rollback;
+		}
+
 		dev->pipes[i].description = drv->endpoints[i];
 		dev->pipes[i].interface_no = my_interface;
@@ -92,16 +139,89 @@
 	void *config_descriptor;
 	size_t config_descriptor_size;
-	int rc = usb_request_get_full_configuration_descriptor_alloc(
-	   &dev->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size);
-	assert(rc == EOK);
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    &dev->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size);
+	if (rc != EOK) {
+		usb_log_error("Failed retrieving configuration of `%s': %s.\n",
+		    dev->ddf_dev->name, str_error(rc));
+		goto rollback;
+	}
 
 	rc = usb_endpoint_pipe_initialize_from_configuration(dev->pipes,
 	   pipe_count, config_descriptor, config_descriptor_size, &dev->wire);
-	assert(rc == EOK);
-
+	if (rc != EOK) {
+		usb_log_error("Failed initializing USB endpoints: %s.\n",
+		    str_error(rc));
+		goto rollback;
+	}
 
 	return EOK;
-}
-
+
+rollback:
+	for (i = 0; i < pipe_count; i++) {
+		if (dev->pipes[i].pipe != NULL) {
+			free(dev->pipes[i].pipe);
+		}
+	}
+	free(dev->pipes);
+
+	return rc;
+}
+
+/** Initialize all endpoint pipes.
+ *
+ * @param drv The driver.
+ * @param dev The device to be initialized.
+ * @return Error code.
+ */
+static int initialize_pipes(usb_driver_t *drv, usb_device_t *dev)
+{
+	int rc;
+
+	rc = usb_device_connection_initialize_from_device(&dev->wire,
+	    dev->ddf_dev);
+	if (rc != EOK) {
+		usb_log_error(
+		    "Failed initializing connection on device `%s'. %s.\n",
+		    dev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	rc = usb_endpoint_pipe_initialize_default_control(&dev->ctrl_pipe,
+	    &dev->wire);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize default control pipe " \
+		    "on device `%s': %s.\n",
+		    dev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	/*
+	 * Initialization of other pipes requires open session on
+	 * default control pipe.
+	 */
+	rc = usb_endpoint_pipe_start_session(&dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_error("Failed to start an IPC session: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	if (driver->endpoints != NULL) {
+		rc = initialize_other_pipes(driver, dev);
+	}
+
+	/* No checking here. */
+	usb_endpoint_pipe_end_session(&dev->ctrl_pipe);
+
+	return rc;
+}
+
+/** Callback when new device is supposed to be controlled by this driver.
+ *
+ * This callback is a wrapper for USB specific version of @c add_device.
+ *
+ * @param gen_dev Device structure as prepared by DDF.
+ * @return Error code.
+ */
 int generic_add_device(ddf_dev_t *gen_dev)
 {
@@ -113,28 +233,20 @@
 
 	usb_device_t *dev = malloc(sizeof(usb_device_t));
-	assert(dev);
+	if (dev == NULL) {
+		usb_log_error("Out of memory when adding device `%s'.\n",
+		    gen_dev->name);
+		return ENOMEM;
+	}
+
 
 	dev->ddf_dev = gen_dev;
+	dev->ddf_dev->driver_data = dev;
 	dev->driver_data = NULL;
 
-	/* Initialize the backing wire abstraction. */
-	rc = usb_device_connection_initialize_from_device(&dev->wire, gen_dev);
-	assert(rc == EOK);
-
-	/* Initialize the default control pipe. */
-	rc = usb_endpoint_pipe_initialize_default_control(&dev->ctrl_pipe,
-	    &dev->wire);
-	assert(rc == EOK);
-
-	rc = usb_endpoint_pipe_start_session(&dev->ctrl_pipe);
-	assert(rc == EOK);
-
-	/* Initialize remaining pipes. */
-	if (driver->endpoints != NULL) {
-		initialize_other_pipes(driver, dev);
-	}
-
-	rc = usb_endpoint_pipe_end_session(&dev->ctrl_pipe);
-	assert(rc == EOK);
+	rc = initialize_pipes(driver, dev);
+	if (rc != EOK) {
+		free(dev);
+		return rc;
+	}
 
 	return driver->ops->add_device(dev);
