Index: .bzrignore
===================================================================
--- .bzrignore	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ .bzrignore	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -94,4 +94,5 @@
 ./uspace/drv/usbhid/usbhid
 ./uspace/drv/usbkbd/usbkbd
+./uspace/drv/usbmast/usbmast
 ./uspace/drv/usbmid/usbmid
 ./uspace/drv/usbmouse/usbmouse
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ boot/arch/amd64/Makefile.inc	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -51,4 +51,5 @@
 	usbkbd \
 	usbhid \
+	usbmast \
 	usbmid \
 	usbmouse \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ uspace/Makefile	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -125,4 +125,5 @@
 		drv/usbhid \
 		drv/usbhub \
+		drv/usbmast \
 		drv/usbmid \
 		drv/usbmouse \
@@ -146,4 +147,5 @@
 		drv/usbhid \
 		drv/usbhub \
+		drv/usbmast \
 		drv/usbmid \
 		drv/usbmouse \
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ uspace/doc/doxygroups.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -251,4 +251,12 @@
 
 	/**
+	 * @defgroup drvusbmast USB mass storage driver
+	 * @ingroup usb
+	 * @brief USB driver for mass storage devices (bulk-only protocol).
+	 * This driver is a only a stub and is currently used only for
+	 * testing that bulk transfers work.
+	 */
+
+	/**
 	 * @defgroup drvusbuhci UHCI driver
 	 * @ingroup usb
Index: uspace/drv/usbhid/usbhid.c
===================================================================
--- uspace/drv/usbhid/usbhid.c	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ uspace/drv/usbhid/usbhid.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -360,5 +360,5 @@
 	rc = usb_hid_check_pipes(hid_dev, dev);
 	if (rc != EOK) {
-		usb_hid_free(&hid_dev);
+		//usb_hid_free(&hid_dev);
 		return rc;
 	}
@@ -368,5 +368,5 @@
 	if (rc != EOK) {
 		usb_log_error("Failed to initialize report parser.\n");
-		usb_hid_free(&hid_dev);
+		//usb_hid_free(&hid_dev);
 		return rc;
 	}
@@ -386,4 +386,6 @@
 			    " device.\n");
 			fallback = true;
+			assert(hid_dev->subdrivers == NULL);
+			assert(hid_dev->subdriver_count == 0);
 		}
 	} else {
@@ -426,5 +428,7 @@
 		usb_log_error("No subdriver for handling this device could be"
 		    " initialized: %s.\n", str_error(rc));
-		usb_hid_free(&hid_dev);
+		usb_log_debug("Subdriver count: %d\n", 
+		    hid_dev->subdriver_count);
+		//usb_hid_free(&hid_dev);
 	} else {
 		bool ok = false;
@@ -550,4 +554,7 @@
 	}
 	
+	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
+	    (*hid_dev)->subdrivers, (*hid_dev)->subdriver_count);
+	
 	assert((*hid_dev)->subdrivers != NULL 
 	    || (*hid_dev)->subdriver_count == 0);
Index: uspace/drv/usbmast/Makefile
===================================================================
--- uspace/drv/usbmast/Makefile	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/Makefile	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2011 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include
+BINARY = usbmast
+
+SOURCES = \
+	main.c \
+	mast.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmast/cmds.h
===================================================================
--- uspace/drv/usbmast/cmds.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/cmds.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef USB_USBMAST_CMDS_H_
+#define USB_USBMAST_CMDS_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint32_t dCBWSignature;
+	uint32_t dCBWTag;
+	uint32_t dCBWDataTransferLength;
+	uint8_t bmCBWFlags;
+	uint8_t bCBWLUN;
+	uint8_t bCBWBLength;
+	uint8_t CBWCB[16];
+} __attribute__((packed)) usb_massstor_cbw_t;
+
+typedef struct {
+	uint32_t dCSWSignature;
+	uint32_t dCSWTag;
+	uint32_t dCSWDataResidue;
+	uint8_t dCSWStatus;
+} __attribute__((packed)) usb_massstor_csw_t;
+
+static inline void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
+    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
+    uint8_t lun, uint8_t cmd_len, uint8_t *cmd)
+{
+	cbw->dCBWSignature = uint32_host2usb(0x43425355);
+	cbw->dCBWTag = tag;
+	cbw->dCBWDataTransferLength = transfer_length;
+
+	cbw->bmCBWFlags = 0;
+	if (dir == USB_DIRECTION_IN) {
+		cbw->bmCBWFlags |= (1 << 7);
+	}
+
+	/* Only lowest 4 bits. */
+	cbw->bCBWLUN = lun & 0x0F;
+
+	/* Only lowest 5 bits. */
+	cbw->bCBWBLength = cmd_len & 0x1F;
+
+	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/main.c
===================================================================
--- uspace/drv/usbmast/main.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/main.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB mass storage driver.
+ */
+#include <usb/devdrv.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/massstor.h>
+#include <errno.h>
+#include <str_error.h>
+#include "cmds.h"
+#include "scsi.h"
+#include "mast.h"
+
+#define NAME "usbmast"
+
+#define BULK_IN_EP 0
+#define BULK_OUT_EP 1
+
+#define GET_BULK_IN(dev) ((dev)->pipes[BULK_IN_EP].pipe)
+#define GET_BULK_OUT(dev) ((dev)->pipes[BULK_OUT_EP].pipe)
+
+static usb_endpoint_description_t bulk_in_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+static usb_endpoint_description_t bulk_out_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_OUT,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+
+usb_endpoint_description_t *mast_endpoints[] = {
+	&bulk_in_ep,
+	&bulk_out_ep,
+	NULL
+};
+
+#define BITS_GET_MASK(type, bitcount) (((type)(1 << (bitcount)))-1)
+#define BITS_GET_MID_MASK(type, bitcount, offset) \
+	((type)( BITS_GET_MASK(type, (bitcount) + (offset)) - BITS_GET_MASK(type, bitcount) ))
+#define BITS_GET(type, number, bitcount, offset) \
+	((type)( (number) & (BITS_GET_MID_MASK(type, bitcount, offset)) ) >> (offset))
+
+#define INQUIRY_RESPONSE_LENGTH 35
+
+static void try_inquiry(usb_device_t *dev)
+{
+	scsi_cmd_inquiry_t inquiry = {
+		.op_code = 0x12,
+		.lun_evpd = 0,
+		.page_code = 0,
+		.alloc_length = INQUIRY_RESPONSE_LENGTH,
+		.ctrl = 0
+	};
+	size_t response_len;
+	uint8_t response[INQUIRY_RESPONSE_LENGTH];
+
+	int rc;
+
+	rc = usb_massstor_data_in(GET_BULK_IN(dev), GET_BULK_OUT(dev),
+	    0xDEADBEEF, 0, (uint8_t *) &inquiry, sizeof(inquiry),
+	    response, INQUIRY_RESPONSE_LENGTH, &response_len);
+
+	if (rc != EOK) {
+		usb_log_error("Failed to probe device %s using %s: %s.\n",
+		   dev->ddf_dev->name, "SCSI:INQUIRY", str_error(rc));
+		return;
+	}
+
+	if (response_len < 8) {
+		usb_log_error("The SCSI response is too short.\n");
+		return;
+	}
+
+	/*
+	 * This is an ugly part of the code. We will parse the returned
+	 * data by hand and try to get as many useful data as possible.
+	 */
+	int device_type = BITS_GET(uint8_t, response[0], 5, 0);
+	int removable = BITS_GET(uint8_t, response[1], 1, 7);
+
+	usb_log_info("SCSI information for device `%s':\n", dev->ddf_dev->name);
+	usb_log_info("  - peripheral device type: %d\n", device_type);
+	usb_log_info("  - removable: %s\n", removable ? "yes" : "no");
+
+	if (response_len < 32) {
+		return;
+	}
+
+	char dev_vendor[9];
+	str_ncpy(dev_vendor, 9, (const char *) &response[8], 8);
+	usb_log_info("  - vendor: '%s'\n", dev_vendor);
+
+	char dev_product[9];
+	str_ncpy(dev_product, 9, (const char *) &response[16], 8);
+	usb_log_info("  - product: '%s'\n", dev_vendor);
+}
+
+/** Callback when new device is attached and recognized as a mass storage.
+ *
+ * @param dev Representation of a the USB device.
+ * @return Error code.
+ */
+static int usbmast_add_device(usb_device_t *dev)
+{
+	int rc;
+	const char *fun_name = "ctl";
+
+	ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
+	    fun_name);
+	if (ctl_fun == NULL) {
+		usb_log_error("Failed to create control function.\n");
+		return ENOMEM;
+	}
+	rc = ddf_fun_bind(ctl_fun);
+	if (rc != EOK) {
+		usb_log_error("Failed to bind control function: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	usb_log_info("Pretending to control mass storage `%s'.\n",
+	    dev->ddf_dev->name);
+	usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_IN_EP].pipe->endpoint_no,
+	    (size_t) dev->pipes[BULK_IN_EP].descriptor->max_packet_size);
+	usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_OUT_EP].pipe->endpoint_no,
+	    (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
+
+	try_inquiry(dev);
+
+	return EOK;
+}
+
+/** USB mass storage driver ops. */
+static usb_driver_ops_t usbmast_driver_ops = {
+	.add_device = usbmast_add_device,
+};
+
+/** USB mass storage driver. */
+static usb_driver_t usbmast_driver = {
+	.name = NAME,
+	.ops = &usbmast_driver_ops,
+	.endpoints = mast_endpoints
+};
+
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&usbmast_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/mast.c
===================================================================
--- uspace/drv/usbmast/mast.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/mast.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Generic functions for USB mass storage (implementation).
+ */
+#include "mast.h"
+#include "cmds.h"
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+
+bool usb_mast_verbose = true;
+
+#define MASTLOG(format, ...) \
+	do { \
+		if (usb_mast_verbose) { \
+			usb_log_debug("USB cl08: " format, ##__VA_ARGS__); \
+		} \
+	} while (false)
+
+/** Request data from mass storage device.
+ *
+ * @param bulk_in_pipe Bulk in pipe to the device.
+ * @param bulk_out_pipe Bulk out pipe to the device.
+ * @param tag Command block wrapper tag (automatically compared with answer).
+ * @param lun LUN index.
+ * @param cmd SCSI command buffer (in SCSI endianness).
+ * @param cmd_size Length of SCSI command @p cmd in bytes.
+ * @param in_buffer Buffer where to store the answer (CSW is not returned).
+ * @param in_buffer_size Size of the buffer (size of the request to the device).
+ * @param received_size Number of actually received bytes.
+ * @return Error code.
+ */
+int usb_massstor_data_in(usb_pipe_t *bulk_in_pipe, usb_pipe_t *bulk_out_pipe,
+    uint32_t tag, uint8_t lun, void *cmd, size_t cmd_size,
+    void *in_buffer, size_t in_buffer_size, size_t *received_size)
+{
+	int rc;
+	size_t act_size;
+
+	/* Prepare CBW - command block wrapper */
+	usb_massstor_cbw_t cbw;
+	usb_massstor_cbw_prepare(&cbw, tag, in_buffer_size,
+	    USB_DIRECTION_IN, lun, cmd_size, cmd);
+
+	/* First, send the CBW. */
+	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
+	MASTLOG("CBW '%s' sent: %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Try to retrieve the data from the device. */
+	act_size = 0;
+	rc = usb_pipe_read(bulk_in_pipe, in_buffer, in_buffer_size, &act_size);
+	MASTLOG("Received %zuB (%s): %s.\n", act_size,
+	    usb_debug_str_buffer((uint8_t *) in_buffer, act_size, 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Read CSW. */
+	usb_massstor_csw_t csw;
+	size_t csw_size;
+	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
+	MASTLOG("CSW '%s' received (%zuB): %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+	if (csw_size != sizeof(csw)) {
+		return ERANGE;
+	}
+
+	if (csw.dCSWTag != tag) {
+		return EBADCHECKSUM;
+	}
+
+	/*
+	 * Determine the actual return value from the CSW.
+	 */
+	if (csw.dCSWStatus != 0) {
+		// FIXME: better error code
+		// FIXME: distinguish 0x01 and 0x02
+		return EXDEV;
+	}
+
+	size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
+	if (residue > in_buffer_size) {
+		return ERANGE;
+	}
+	if (act_size != in_buffer_size - residue) {
+		return ERANGE;
+	}
+	if (received_size != NULL) {
+		*received_size = in_buffer_size - residue;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/mast.h
===================================================================
--- uspace/drv/usbmast/mast.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/mast.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/** @file
+ * Generic functions for USB mass storage.
+ */
+
+#ifndef USB_USBMAST_MAST_H_
+#define USB_USBMAST_MAST_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/pipes.h>
+
+int usb_massstor_data_in(usb_pipe_t *, usb_pipe_t *, uint32_t, uint8_t,
+    void *, size_t, void *, size_t, size_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/scsi.h
===================================================================
--- uspace/drv/usbmast/scsi.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/scsi.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/** @file
+ * SCSI related structures.
+ */
+
+#ifndef USB_USBMAST_SCSI_H_
+#define USB_USBMAST_SCSI_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint8_t op_code;
+	uint8_t lun_evpd;
+	uint8_t page_code;
+	uint16_t alloc_length;
+	uint8_t ctrl;
+} __attribute__((packed)) scsi_cmd_inquiry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/usbmast.ma
===================================================================
--- uspace/drv/usbmast/usbmast.ma	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/drv/usbmast/usbmast.ma	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,1 @@
+50 usb&interface&class=mass-storage&subclass=0x06&protocol=0x50
Index: uspace/lib/usb/include/usb/classes/massstor.h
===================================================================
--- uspace/lib/usb/include/usb/classes/massstor.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
+++ uspace/lib/usb/include/usb/classes/massstor.h	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusb
+ * @{
+ */
+/** @file
+ * USB mass storage related functions and constants.
+ */
+#ifndef LIBUSB_CLASS_MASSSTOR_H_
+#define LIBUSB_CLASS_MASSSTOR_H_
+
+#include <sys/types.h>
+
+/** USB mass storage subclasses. */
+typedef enum {
+	USB_MASSSTOR_SUBCLASS_RBC = 0x01,
+	/** Also known as MMC-5. */
+	USB_MASSSTOR_SUBCLASS_ATAPI = 0x02,
+	USB_MASSSTOR_SUBCLASS_UFI = 0x04,
+	USB_MASSSTOR_SUBCLASS_SCSI = 0x06,
+	USB_MASSSTOR_SUBCLASS_LSDFS = 0x07,
+	USB_MASSSTOR_SUBCLASS_IEEE1667 = 0x08,
+	USB_MASSSTOR_SUBCLASS_VENDOR = 0xFF
+} usb_massstor_subclass_t;
+
+/** USB mass storage interface protocols. */
+typedef enum {
+	/** CBI transport with command completion interrupt. */
+	USB_MASSSTOR_PROTOCOL_CBI_CC = 0x00,
+	/** CBI transport with no command completion interrupt. */
+	USB_MASSSTOR_PROTOCOL_CBI = 0x01,
+	/** Bulk only transport. */
+	USB_MASSSTOR_PROTOCOL_BBB = 0x50,
+	/** USB attached SCSI. */
+	USB_MASSSTOR_PROTOCOL_UAS = 0x62,
+	USB_MASSSTOR_PROTOCOL_VENDOR = 0xFF
+} usb_massstor_protocol_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hidreport.c
===================================================================
--- uspace/lib/usb/src/hidreport.c	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ uspace/lib/usb/src/hidreport.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -119,14 +119,4 @@
 	uint16_t length =  hid_desc->report_desc_info.length;
 	size_t actual_size = 0;
-	
-	/*
-	 * Start session for the control transfer.
-	 */
-	int sess_rc = usb_pipe_start_session(&dev->ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
 
 	/*
@@ -162,16 +152,4 @@
 		    "%u)\n", actual_size, length);
 		return EINVAL;
-	}
-	
-	/*
-	 * End session for the control transfer.
-	 */
-	sess_rc = usb_pipe_end_session(&dev->ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to end a session: %s.\n",
-		    str_error(sess_rc));
-		free(*report_desc);
-		*report_desc = NULL;
-		return sess_rc;
 	}
 	
Index: uspace/lib/usb/src/hidreq.c
===================================================================
--- uspace/lib/usb/src/hidreq.c	(revision 90634843235950d35639836d15c8ef3662641fe1)
+++ uspace/lib/usb/src/hidreq.c	(revision ff76509a4cdd6b4965cdb4d458fedb849ef76ba2)
@@ -56,7 +56,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_set_report(usb_pipe_t *ctrl_pipe, int iface_no,
@@ -79,12 +77,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 	
 	uint16_t value = 0;
@@ -97,16 +88,8 @@
 	    USB_HIDREQ_SET_REPORT, value, iface_no, buffer, buf_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -123,7 +106,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_set_protocol(usb_pipe_t *ctrl_pipe, int iface_no,
@@ -146,12 +127,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	usb_log_debug("Sending Set_Protocol request to the device ("
@@ -162,16 +136,8 @@
 	    USB_HIDREQ_SET_PROTOCOL, protocol, iface_no, NULL, 0);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -189,7 +155,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_set_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t duration)
@@ -211,12 +175,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	usb_log_debug("Sending Set_Idle request to the device ("
@@ -229,16 +186,8 @@
 	    USB_HIDREQ_SET_IDLE, value, iface_no, NULL, 0);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -259,7 +208,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_get_report(usb_pipe_t *ctrl_pipe, int iface_no, 
@@ -283,12 +230,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	uint16_t value = 0;
@@ -302,16 +242,8 @@
 	    actual_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -328,7 +260,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_get_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 
@@ -351,12 +281,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;	
 
 	usb_log_debug("Sending Get_Protocol request to the device ("
@@ -370,16 +293,8 @@
 	    USB_HIDREQ_GET_PROTOCOL, 0, iface_no, buffer, 1, &actual_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -427,12 +342,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	usb_log_debug("Sending Get_Idle request to the device ("
@@ -448,16 +356,8 @@
 	    &actual_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
