Index: uspace/drv/vhc/hubops.c
===================================================================
--- uspace/drv/vhc/hubops.c	(revision d5e76686497cace0d5ab653dee609bfc1fc6974b)
+++ uspace/drv/vhc/hubops.c	(revision 266d0871dba029aae0bcd196cb56080cb90b71b7)
@@ -59,6 +59,4 @@
 static int on_get_descriptor(struct usbvirt_device *dev,
     usb_device_request_setup_packet_t *request, uint8_t *data);
-static int on_set_configuration(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,
@@ -83,18 +81,29 @@
 }
 
-/** Callback for SET_CONFIGURATION request. */
-int on_set_configuration(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{
-	/* We must suspend power source to all ports. */
+static void change_all_ports_state(hub_device_t *hub, hub_port_state_t state)
+{
 	size_t i;
 	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		hub_port_t *port = &hub_dev.ports[i];
-		
-		set_port_state(port, HUB_PORT_STATE_POWERED_OFF);
-	}
-	
-	/* Let the framework handle the rest of the job. */
-	return EFORWARD;
+		hub_port_t *port = &hub->ports[i];
+		set_port_state(port, state);
+	}
+}
+
+/** Callback when device changes states. */
+static void on_state_change(struct usbvirt_device *dev,
+    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state)
+{
+	switch (new_state) {
+		case USBVIRT_STATE_CONFIGURED:
+			change_all_ports_state(&hub_dev,
+			    HUB_PORT_STATE_POWERED_OFF);
+			break;
+		case USBVIRT_STATE_ADDRESS:
+			change_all_ports_state(&hub_dev,
+			    HUB_PORT_STATE_NOT_CONFIGURED);
+			break;
+		default:
+			break;
+	}
 }
 
@@ -518,9 +527,4 @@
 static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
 	{
-		STD_REQ(DIR_OUT, REC_DEVICE, USB_DEVREQ_SET_CONFIGURATION),
-		.name = "SetConfiguration",
-		.callback = on_set_configuration
-	},
-	{
 		STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
 		.name = "GetDescriptor",
@@ -585,5 +589,6 @@
 	.control_transfer_handlers = endpoint_zero_handlers,
 	.on_data = NULL,
-	.on_data_request = on_data_request
+	.on_data_request = on_data_request,
+	.on_state_change = on_state_change,
 };
 
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision d5e76686497cace0d5ab653dee609bfc1fc6974b)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 266d0871dba029aae0bcd196cb56080cb90b71b7)
@@ -52,4 +52,13 @@
 } usbvirt_request_recipient_t;
 
+/** Possible states of virtual USB device.
+ * Notice that these are not 1:1 mappings to those in USB specification.
+ */
+typedef enum {
+	USBVIRT_STATE_DEFAULT,
+	USBVIRT_STATE_ADDRESS,
+	USBVIRT_STATE_CONFIGURED
+} usbvirt_device_state_t;
+
 typedef struct usbvirt_device usbvirt_device_t;
 struct usbvirt_control_transfer;
@@ -96,4 +105,17 @@
 	usb_direction_t (*decide_control_transfer_direction)(
 	    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+	/** Callback when device changes its state.
+	 *
+	 * It is correct that this function is called when both states
+	 * are equal (e.g. this function is called during SET_CONFIGURATION
+	 * request done on already configured device).
+	 *
+	 * @warning The value of <code>dev->state</code> before calling
+	 * this function is not specified (i.e. can be @p old_state or
+	 * @p new_state).
+	 */
+	void (*on_state_change)(usbvirt_device_t *dev,
+	    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state);
 } usbvirt_device_ops_t;
 
@@ -130,13 +152,4 @@
 	uint8_t current_configuration;
 } usbvirt_descriptors_t;
-
-/** Possible states of virtual USB device.
- * Notice that these are not 1:1 mappings to those in USB specification.
- */
-typedef enum {
-	USBVIRT_STATE_DEFAULT,
-	USBVIRT_STATE_ADDRESS,
-	USBVIRT_STATE_CONFIGURED
-} usbvirt_device_state_t;
 
 /** Information about on-going control transfer.
Index: uspace/lib/usbvirt/src/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/src/ctrlpipe.c	(revision d5e76686497cace0d5ab653dee609bfc1fc6974b)
+++ uspace/lib/usbvirt/src/ctrlpipe.c	(revision 266d0871dba029aae0bcd196cb56080cb90b71b7)
@@ -154,8 +154,9 @@
 		 * setting address when in configured state).
 		 */
+		usbvirt_device_state_t new_state;
 		if (device->new_address == 0) {
-			device->state = USBVIRT_STATE_DEFAULT;
+			new_state = USBVIRT_STATE_DEFAULT;
 		} else {
-			device->state = USBVIRT_STATE_ADDRESS;
+			new_state = USBVIRT_STATE_ADDRESS;
 		}
 		device->address = device->new_address;
@@ -163,4 +164,10 @@
 		device->new_address = -1;
 		
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    new_state);
+		}
+		device->state = new_state;
+
 		device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
 		    "device address changed to %d (state %s)",
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision d5e76686497cace0d5ab653dee609bfc1fc6974b)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 266d0871dba029aae0bcd196cb56080cb90b71b7)
@@ -157,4 +157,8 @@
 	
 	if (configuration_value == 0) {
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    USBVIRT_STATE_ADDRESS);
+		}
 		device->state = USBVIRT_STATE_ADDRESS;
 	} else {
@@ -163,4 +167,8 @@
 		* user selected existing configuration.
 		*/
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    USBVIRT_STATE_CONFIGURED);
+		}
 		device->state = USBVIRT_STATE_CONFIGURED;
 		if (device->descriptors) {
