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) {
