Index: uspace/app/virtusbkbd/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision 8f8ae1fd40abf46fa26616612cd5c3ff31aee970)
+++ uspace/app/virtusbkbd/virtusbkbd.c	(revision 7feeb848f2e12de48c167eded31acbb40ded0caf)
@@ -76,11 +76,4 @@
 }
 
-static int on_class_request(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{	
-	printf("%s: class request (%d)\n", NAME, (int) request->request);
-	
-	return EOK;
-}
 
 /** Compares current and last status of pressed keys.
@@ -138,4 +131,23 @@
 }
 
+static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
+	{
+		.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(
+		    USB_DIRECTION_IN,
+		    USBVIRT_REQUEST_TYPE_STANDARD,
+		    USBVIRT_REQUEST_RECIPIENT_DEVICE),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.callback = stdreq_on_get_descriptor
+	},
+	{
+		.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(
+		    USB_DIRECTION_IN,
+		    USBVIRT_REQUEST_TYPE_CLASS,
+		    USBVIRT_REQUEST_RECIPIENT_DEVICE),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.callback = stdreq_on_get_descriptor
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
+};
 
 /** Keyboard callbacks.
@@ -143,7 +155,5 @@
  */
 static usbvirt_device_ops_t keyboard_ops = {
-	.on_standard_request[USB_DEVREQ_GET_DESCRIPTOR]
-	    = stdreq_on_get_descriptor,
-	.on_class_device_request = on_class_request,
+	.control_transfer_handlers = endpoint_zero_handlers,
 	.on_data = on_incoming_data,
 	.on_data_request = on_request_for_data
Index: uspace/drv/vhc/hubops.c
===================================================================
--- uspace/drv/vhc/hubops.c	(revision 8f8ae1fd40abf46fa26616612cd5c3ff31aee970)
+++ uspace/drv/vhc/hubops.c	(revision 7feeb848f2e12de48c167eded31acbb40ded0caf)
@@ -61,6 +61,4 @@
 static int on_set_configuration(struct usbvirt_device *dev,
     usb_device_request_setup_packet_t *request, uint8_t *data);
-static int on_class_request(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data);
 static int on_data_request(struct usbvirt_device *dev,
     usb_endpoint_t endpoint,
@@ -69,13 +67,5 @@
 static void clear_port_status_change_nl(hub_port_t *, uint16_t);
 static void set_port_state_nl(hub_port_t *, hub_port_state_t);
-
-/** Hub operations. */
-usbvirt_device_ops_t hub_ops = {
-	.on_standard_request[USB_DEVREQ_GET_DESCRIPTOR] = on_get_descriptor,
-	.on_standard_request[USB_DEVREQ_SET_CONFIGURATION] = on_set_configuration,
-	.on_class_device_request = on_class_request,
-	.on_data = NULL,
-	.on_data_request = on_data_request
-};
+static int get_port_status(uint16_t portindex);
 
 /** Callback for GET_DESCRIPTOR request. */
@@ -300,5 +290,5 @@
 }
 
-static int get_port_status(uint16_t portindex)
+int get_port_status(uint16_t portindex)
 {
 	_GET_PORT(port, portindex);
@@ -384,68 +374,4 @@
 
 
-/** Callback for class request. */
-static int on_class_request(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{	
-	dprintf(2, "hub class request (%d)", (int) request->request);
-	
-	uint8_t recipient = request->request_type & 31;
-	uint8_t direction = request->request_type >> 7;
-	
-#define _VERIFY(cond) \
-	do { \
-		if (!(cond)) { \
-			dprintf(0, "WARN: invalid class request (%s not met).\n", \
-			    NAME, #cond); \
-			return EINVAL; \
-		} \
-	} while (0)
-	
-	switch (request->request) {
-		case USB_HUB_REQUEST_CLEAR_FEATURE:
-			_VERIFY(direction == 0);
-			_VERIFY(request->length == 0);
-			if (recipient == 0) {
-				_VERIFY(request->index == 0);
-				return clear_hub_feature(request->value);
-			} else {
-				_VERIFY(recipient == 3);
-				return clear_port_feature(request->value,
-				    request->index);
-			}
-			
-		case USB_HUB_REQUEST_GET_STATE:
-			return get_bus_state(request->index);
-			
-		case USB_HUB_REQUEST_GET_DESCRIPTOR:
-			return get_hub_descriptor(dev, request->value_low,
-			    request->value_high, request->length);
-			
-		case USB_HUB_REQUEST_GET_STATUS:
-			if (recipient == 0) {
-				return get_hub_status();
-			} else {
-				return get_port_status(request->index);
-			}
-			
-		case USB_HUB_REQUEST_SET_FEATURE:
-			if (recipient == 0) {
-				return set_hub_feature(request->value);
-			} else {
-				return set_port_feature(request->value, request->index);
-			}
-			
-		default:
-			dprintf(0, "WARN: unknown request (%d)!\n",
-			    request->request);
-			break;
-	}
-	
-#undef _VERIFY	
-
-
-	return EOK;
-}
-
 void clear_port_status_change_nl(hub_port_t *port, uint16_t change)
 {
@@ -509,4 +435,145 @@
 
 
+
+static int req_clear_hub_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return clear_hub_feature(request->value);
+}
+
+static int req_clear_port_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return clear_port_feature(request->value, request->index);
+}
+
+static int req_get_bus_state(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return get_bus_state(request->index);
+}
+
+static int req_get_hub_descriptor(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return get_hub_descriptor(dev, request->value_low,
+	    request->value_high, request->length);
+}
+
+static int req_get_hub_status(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return get_hub_status();
+}
+
+static int req_get_port_status(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return get_port_status(request->index);
+}
+
+static int req_set_hub_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return set_hub_feature(request->value);
+}
+
+static int req_set_port_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return set_port_feature(request->value, request->index);
+}
+
+#define CLASS_REQ_IN(recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_IN, \
+	USBVIRT_REQUEST_TYPE_CLASS, recipient)
+#define CLASS_REQ_OUT(recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_OUT, \
+	USBVIRT_REQUEST_TYPE_CLASS, recipient)
+
+#define REC_OTHER USBVIRT_REQUEST_RECIPIENT_OTHER
+#define REC_DEVICE USBVIRT_REQUEST_RECIPIENT_DEVICE
+#define DIR_IN USB_DIRECTION_IN
+#define DIR_OUT USB_DIRECTION_OUT
+
+#define CLASS_REQ(direction, recipient, req) \
+	.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_CLASS, recipient), \
+	.request = req
+
+#define STD_REQ(direction, recipient, req) \
+	.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_STANDARD, recipient), \
+	.request = req
+
+/** Hub operations on control endpoint zero. */
+static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
+	{
+		STD_REQ(DIR_OUT, REC_DEVICE, USB_DEVREQ_SET_CONFIGURATION),
+		.callback = on_set_configuration
+	},
+	{
+		STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.callback = on_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.callback = on_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
+		.callback = req_get_port_status
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
+		.callback = req_clear_hub_feature
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
+		.callback = req_clear_port_feature
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATE),
+		.callback = req_get_bus_state
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
+		.callback = req_get_hub_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_STATUS),
+		.callback = req_get_hub_status
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
+		.callback = req_get_port_status
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
+		.callback = req_set_hub_feature
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_SET_FEATURE),
+		.callback = req_set_port_feature
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
+};
+
+
+/** Hub operations. */
+usbvirt_device_ops_t hub_ops = {
+	.control_transfer_handlers = endpoint_zero_handlers,
+	.on_data = NULL,
+	.on_data_request = on_data_request
+};
+
 /**
  * @}
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision 8f8ae1fd40abf46fa26616612cd5c3ff31aee970)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 7feeb848f2e12de48c167eded31acbb40ded0caf)
@@ -40,4 +40,16 @@
 #include <usb/devreq.h>
 
+typedef enum {
+	USBVIRT_REQUEST_TYPE_STANDARD = 0,
+	USBVIRT_REQUEST_TYPE_CLASS = 1
+} usbvirt_request_type_t;
+
+typedef enum {
+	USBVIRT_REQUEST_RECIPIENT_DEVICE = 0,
+	USBVIRT_REQUEST_RECIPIENT_INTERFACE = 1,
+	USBVIRT_REQUEST_RECIPIENT_ENDPOINT = 2,
+	USBVIRT_REQUEST_RECIPIENT_OTHER = 3
+} usbvirt_request_recipient_t;
+
 typedef struct usbvirt_device usbvirt_device_t;
 struct usbvirt_control_transfer;
@@ -47,13 +59,26 @@
 	uint8_t *data);
 
+typedef int (*usbvirt_control_request_callback_t)(usbvirt_device_t *dev,
+	usb_device_request_setup_packet_t *request,
+	uint8_t *data);
+
+typedef struct {
+	uint8_t request_type;
+	uint8_t request;
+	usbvirt_control_request_callback_t callback;
+} usbvirt_control_transfer_handler_t;
+
+#define USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, type, recipient) \
+	((((direction) == USB_DIRECTION_IN) ? 1 : 0) << 7) \
+	| (((type) & 3) << 5) \
+	| (((recipient) & 31))
+
+#define USBVIRT_CONTROL_TRANSFER_HANDLER_LAST { 0, 0, NULL }
+
 /** Device operations. */
 typedef struct {
-	/** Callbacks for standard device requests.
-	 * The callbacks are indexed by usb_stddevreq_t enum.
-	 */
-	usbvirt_on_device_request_t on_standard_request[USB_DEVREQ_LAST_STD];
-	/** Callback for class-specific USB request. */
-	usbvirt_on_device_request_t on_class_device_request;
-	
+	/** Callbacks for transfers over control pipe zero. */
+	usbvirt_control_transfer_handler_t *control_transfer_handlers;
+
 	int (*on_control_transfer)(usbvirt_device_t *dev,
 	    usb_endpoint_t endpoint, struct usbvirt_control_transfer *transfer);
Index: uspace/lib/usbvirt/src/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/src/ctrlpipe.c	(revision 8f8ae1fd40abf46fa26616612cd5c3ff31aee970)
+++ uspace/lib/usbvirt/src/ctrlpipe.c	(revision 7feeb848f2e12de48c167eded31acbb40ded0caf)
@@ -37,32 +37,44 @@
 #include "private.h"
 
-#define REQUEST_TYPE_STANDARD 0 
-#define REQUEST_TYPE_CLASS 1
+/** Compares handler type with request packet type.
+ *
+ * @param handler Handler.
+ * @param request_packet Request packet.
+ * @return Whether handler can serve this packet.
+ */
+static bool is_suitable_handler(usbvirt_control_transfer_handler_t *handler,
+    usb_device_request_setup_packet_t *request_packet)
+{
+	return (
+	    (handler->request_type == request_packet->request_type)
+	    && (handler->request == request_packet->request));
 
-#define GET_MIDBITS_MASK(size, shift) \
-	(((1 << size) - 1) << shift)
-#define GET_MIDBITS(value, size, shift) \
-	((value & GET_MIDBITS_MASK(size, shift)) >> shift)
+}
+
+/** Find suitable transfer handler for given request packet.
+ *
+ * @param handlers Array of available handlers.
+ * @param request_packet Request SETUP packet.
+ * @return Handler or NULL.
+ */
+static usbvirt_control_transfer_handler_t *find_handler(
+    usbvirt_control_transfer_handler_t *handlers,
+    usb_device_request_setup_packet_t *request_packet)
+{
+	if (handlers == NULL) {
+		return NULL;
+	}
+
+	while (handlers->callback != NULL) {
+		if (is_suitable_handler(handlers, request_packet)) {
+			return handlers;
+		}
+		handlers++;
+	}
+
+	return NULL;
+}
 
 
-static const char *str_request_type(int type)
-{
-	switch (type) {
-		case REQUEST_TYPE_STANDARD:
-			return "standard";
-		case REQUEST_TYPE_CLASS:
-			return "class";
-		default:
-			return "unknown";
-	}
-}
-
-/** Tell request type.
- * By type is meant either standard, class, vendor or other.
- */
-static int request_get_type(uint8_t request_type)
-{
-	return GET_MIDBITS(request_type, 2, 5);
-}
 
 /** Handle communication over control pipe zero.
@@ -77,28 +89,39 @@
 	}
 	
-	usb_device_request_setup_packet_t *request = (usb_device_request_setup_packet_t *) transfer->request;
-	uint8_t *remaining_data = transfer->data;
+	usb_device_request_setup_packet_t *request
+	    = (usb_device_request_setup_packet_t *) transfer->request;
+	printf("Request: %d,%d\n", request->request_type, request->request);
 	
-	int type = request_get_type(request->request_type);
-	
-	int rc = EOK;
-	
-	device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
-	    "request type: %s", str_request_type(type));
-	
-	switch (type) {
-		case REQUEST_TYPE_STANDARD:
-			rc = handle_std_request(device, request, remaining_data);
-			break;
-		case REQUEST_TYPE_CLASS:
-			if (DEVICE_HAS_OP(device, on_class_device_request)) {
-				rc = device->ops->on_class_device_request(device,
-				    request, remaining_data);
-			}
-			break;
-		default:
-			break;
+	/*
+	 * First, see whether user provided its own callback.
+	 */
+	int rc = EFORWARD;
+	if (device->ops) {
+		usbvirt_control_transfer_handler_t *user_handler
+		    = find_handler(device->ops->control_transfer_handlers,
+		    request);
+		if (user_handler != NULL) {
+			rc = user_handler->callback(device, request,
+			    transfer->data);
+		}
+	}
+
+	/*
+	 * If there was no user callback or the callback returned EFORWARD,
+	 * we need to run a local handler.
+	 */
+	if (rc == EFORWARD) {
+		usbvirt_control_transfer_handler_t *lib_handler
+		    = find_handler(control_pipe_zero_local_handlers,
+		    request);
+		if (lib_handler != NULL) {
+			rc = lib_handler->callback(device, request,
+			    transfer->data);
+		}
 	}
 	
+	/*
+	 * Check for SET_ADDRESS finalization.
+	 */
 	if (device->new_address != -1) {
 		/*
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision 8f8ae1fd40abf46fa26616612cd5c3ff31aee970)
+++ uspace/lib/usbvirt/src/private.h	(revision 7feeb848f2e12de48c167eded31acbb40ded0caf)
@@ -87,4 +87,6 @@
 }
 
+extern usbvirt_control_transfer_handler_t control_pipe_zero_local_handlers[];
+
 #endif
 /**
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision 8f8ae1fd40abf46fa26616612cd5c3ff31aee970)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 7feeb848f2e12de48c167eded31acbb40ded0caf)
@@ -40,8 +40,4 @@
 #include "private.h"
 
-
-typedef int (*usbvirt_stdreq_handler_t)(usbvirt_device_t *,
-usb_device_request_setup_packet_t *, uint8_t *);
-
 /*
  * All sub handlers must return EFORWARD to inform the caller that
@@ -177,42 +173,29 @@
 }
 
-static usbvirt_stdreq_handler_t local_handlers[USB_DEVREQ_LAST_STD] = {
-	[USB_DEVREQ_GET_DESCRIPTOR] = handle_get_descriptor,
-	[USB_DEVREQ_SET_ADDRESS] = handle_set_address,
-	[USB_DEVREQ_SET_CONFIGURATION] = handle_set_configuration
+
+#define MAKE_BM_REQUEST(direction, recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_STANDARD, recipient)
+#define MAKE_BM_REQUEST_DEV(direction) \
+	MAKE_BM_REQUEST(direction, USBVIRT_REQUEST_RECIPIENT_DEVICE)
+
+usbvirt_control_transfer_handler_t control_pipe_zero_local_handlers[] = {
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_IN),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.callback = handle_get_descriptor
+	},
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_OUT),
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.callback = handle_set_address
+	},
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_OUT),
+		.request = USB_DEVREQ_SET_CONFIGURATION,
+		.callback = handle_set_configuration
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
 };
-
-/** Handle standard device request. */
-int handle_std_request(usbvirt_device_t *device,
-    usb_device_request_setup_packet_t *request_packet, uint8_t *data)
-{
-	int request = request_packet->request;
-
-	device->lib_debug(device, 3, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
-	    "handling standard request %d", request);
-
-	if (request >= USB_DEVREQ_LAST_STD) {
-		return ENOTSUP;
-	}
-	
-	int rc = EFORWARD;
-	if ((device->ops)
-	    && (device->ops->on_standard_request[request])) {
-		rc = device->ops->on_standard_request[request](device,
-		    request_packet, data);
-	}
-
-	if (rc == EFORWARD) {
-		if (local_handlers[request]) {
-			rc = local_handlers[request](device,
-			    request_packet, data);
-		} else {
-			rc = ENOTSUP;
-		}
-	}
-
-	assert(rc != EFORWARD);
-	return rc;
-}
 
 /**
