diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index c0bfc35..36c90a3 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -380,6 +380,17 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value,
 
     ret = usb_desc_handle_control(dev, request, value, index, length, data);
     if (ret >= 0) {
+        switch (request) {
+        case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+            s->config = 0;
+            break;
+        case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+            s->config = 1;
+            usb_bt_fifo_reset(&s->evt);
+            usb_bt_fifo_reset(&s->acl);
+            usb_bt_fifo_reset(&s->sco);
+            break;
+        }
         return ret;
     }
 
@@ -413,23 +424,6 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        s->config = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        if (value != 1 && value != 0) {
-            printf("%s: Wrong SET_CONFIGURATION request (%i)\n",
-                            __FUNCTION__, value);
-            goto fail;
-        }
-        s->config = 1;
-        usb_bt_fifo_reset(&s->evt);
-        usb_bt_fifo_reset(&s->acl);
-        usb_bt_fifo_reset(&s->sco);
-        break;
     case InterfaceRequest | USB_REQ_GET_INTERFACE:
         if (value != 0 || (index & ~1) || length != 1)
             goto fail;
@@ -544,8 +538,7 @@ static void usb_bt_handle_destroy(USBDevice *dev)
 
 static int usb_bt_initfn(USBDevice *dev)
 {
-    struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev);
-    s->dev.speed = USB_SPEED_HIGH;
+    usb_desc_init(dev);
     return 0;
 }
 
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index 3e87f46..14c9e11 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -153,6 +153,16 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
 
 /* ------------------------------------------------------------------ */
 
+void usb_desc_init(USBDevice *dev)
+{
+    const USBDesc *desc = dev->info->usb_desc;
+
+    assert(desc != NULL);
+    dev->speed  = USB_SPEED_FULL;
+    dev->device = desc->full;
+    dev->config = dev->device->confs;
+}
+
 void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str)
 {
     USBDescString *s;
@@ -230,12 +240,12 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
 
     switch(type) {
     case USB_DT_DEVICE:
-        ret = usb_desc_device(&desc->id, desc->full, buf, sizeof(buf));
+        ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
         trace_usb_desc_device(dev->addr, len, ret);
         break;
     case USB_DT_CONFIG:
-        if (index < desc->full->bNumConfigurations) {
-            ret = usb_desc_config(desc->full->confs + index, buf, sizeof(buf));
+        if (index < dev->device->bNumConfigurations) {
+            ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf));
         }
         trace_usb_desc_config(dev->addr, index, len, ret);
         break;
@@ -262,7 +272,7 @@ int usb_desc_handle_control(USBDevice *dev, int request, int value,
                             int index, int length, uint8_t *data)
 {
     const USBDesc *desc = dev->info->usb_desc;
-    int ret = -1;
+    int i, ret = -1;
 
     assert(desc != NULL);
     switch(request) {
@@ -275,6 +285,20 @@ int usb_desc_handle_control(USBDevice *dev, int request, int value,
     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
         ret = usb_desc_get_descriptor(dev, value, data, length);
         break;
+
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = dev->config->bConfigurationValue;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        for (i = 0; i < dev->device->bNumConfigurations; i++) {
+            if (dev->device->confs[i].bConfigurationValue == value) {
+                dev->config = dev->device->confs + i;
+                ret = 0;
+            }
+        }
+        trace_usb_set_config(dev->addr, value, ret);
+        break;
     }
     return ret;
 }
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
index 20fc400..d441725 100644
--- a/hw/usb-desc.h
+++ b/hw/usb-desc.h
@@ -78,6 +78,7 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
 int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
 
 /* control message emulation helpers */
+void usb_desc_init(USBDevice *dev);
 void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
 const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
 int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 72daddf..21c0c72 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -695,13 +695,6 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -822,7 +815,8 @@ static void usb_hid_handle_destroy(USBDevice *dev)
 static int usb_hid_initfn(USBDevice *dev, int kind)
 {
     USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
-    s->dev.speed = USB_SPEED_FULL;
+
+    usb_desc_init(dev);
     s->kind = kind;
 
     if (s->kind == USB_MOUSE) {
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 51a67a2..d21dfc0 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -297,13 +297,6 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -541,7 +534,7 @@ static int usb_hub_initfn(USBDevice *dev)
     USBHubPort *port;
     int i;
 
-    s->dev.speed = USB_SPEED_FULL;
+    usb_desc_init(dev);
     for (i = 0; i < NUM_PORTS; i++) {
         port = &s->ports[i];
         usb_register_port(usb_bus_from_device(dev),
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index b54ccbc..56c6f3d 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -261,13 +261,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -502,7 +495,7 @@ static int usb_msd_initfn(USBDevice *dev)
         usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial);
     }
 
-    s->dev.speed = USB_SPEED_FULL;
+    usb_desc_init(dev);
     scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
     s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0);
     if (!s->scsi_dev) {
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 1a57ef7..e260c44 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -626,7 +626,6 @@ struct rndis_response {
 typedef struct USBNetState {
     USBDevice dev;
 
-    unsigned int rndis;
     enum rndis_state rndis_state;
     uint32_t medium;
     uint32_t speed;
@@ -647,6 +646,11 @@ typedef struct USBNetState {
     QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
 } USBNetState;
 
+static int is_rndis(USBNetState *s)
+{
+    return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
+}
+
 static int ndis_query(USBNetState *s, uint32_t oid,
                       uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
                       size_t outlen)
@@ -1076,8 +1080,9 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
         break;
 
     case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
-        if (!s->rndis || value || index != 0)
+        if (!is_rndis(s) || value || index != 0) {
             goto fail;
+        }
 #ifdef TRAFFIC_DEBUG
         {
             unsigned int i;
@@ -1094,8 +1099,9 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
         break;
 
     case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
-        if (!s->rndis || value || index != 0)
+        if (!is_rndis(s) || value || index != 0) {
             goto fail;
+        }
         ret = rndis_get_response(s, data);
         if (!ret) {
             data[0] = 0;
@@ -1115,27 +1121,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
 #endif
         break;
 
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE;
-        ret = 1;
-        break;
-
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        switch (value & 0xff) {
-        case DEV_CONFIG_VALUE:
-            s->rndis = 0;
-            break;
-
-        case DEV_RNDIS_CONFIG_VALUE:
-            s->rndis = 1;
-            break;
-
-        default:
-            goto fail;
-        }
-        ret = 0;
-        break;
-
     case DeviceRequest | USB_REQ_GET_INTERFACE:
     case InterfaceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
@@ -1206,7 +1191,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
     memcpy(p->data, &s->in_buf[s->in_ptr], ret);
     s->in_ptr += ret;
     if (s->in_ptr >= s->in_len &&
-                    (s->rndis || (s->in_len & (64 - 1)) || !ret)) {
+                    (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
         /* no short packet necessary */
         s->in_ptr = s->in_len = 0;
     }
@@ -1255,7 +1240,7 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
     memcpy(&s->out_buf[s->out_ptr], p->data, sz);
     s->out_ptr += sz;
 
-    if (!s->rndis) {
+    if (!is_rndis(s)) {
         if (ret < 64) {
             qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr);
             s->out_ptr = 0;
@@ -1326,7 +1311,7 @@ static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t si
     USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
     struct rndis_packet_msg_type *msg;
 
-    if (s->rndis) {
+    if (is_rndis(s)) {
         msg = (struct rndis_packet_msg_type *) s->in_buf;
         if (!s->rndis_state == RNDIS_DATA_INITIALIZED)
             return -1;
@@ -1362,8 +1347,9 @@ static int usbnet_can_receive(VLANClientState *nc)
 {
     USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-    if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED)
+    if (is_rndis(s) && !s->rndis_state == RNDIS_DATA_INITIALIZED) {
         return 1;
+    }
 
     return !s->in_len;
 }
@@ -1396,9 +1382,8 @@ static int usb_net_initfn(USBDevice *dev)
 {
     USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
 
-    s->dev.speed  = USB_SPEED_FULL;
+    usb_desc_init(dev);
 
-    s->rndis = 1;
     s->rndis_state = RNDIS_UNINITIALIZED;
     QTAILQ_INIT(&s->rndis_resp);
 
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index c1f31c7..2bdb10b 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -254,13 +254,6 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -507,7 +500,8 @@ static void usb_serial_event(void *opaque, int event)
 static int usb_serial_initfn(USBDevice *dev)
 {
     USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
-    s->dev.speed = USB_SPEED_FULL;
+
+    usb_desc_init(dev);
 
     if (!s->cs) {
         error_report("Property chardev is required");
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index ad1c3ae..3a98e80 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -284,13 +284,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
         }
         ret = 0;
         break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -373,7 +366,7 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
 static int usb_wacom_initfn(USBDevice *dev)
 {
     USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
-    s->dev.speed = USB_SPEED_FULL;
+    usb_desc_init(dev);
     s->changed = 1;
     return 0;
 }
diff --git a/hw/usb.h b/hw/usb.h
index 760550d..b8f13cc 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -164,6 +164,8 @@ struct USBDevice {
     int setup_index;
 
     QLIST_HEAD(, USBDescString) strings;
+    const USBDescDevice *device;
+    const USBDescConfig *config;
 };
 
 struct USBDeviceInfo {
diff --git a/trace-events b/trace-events
index 3372b78..2962d60 100644
--- a/trace-events
+++ b/trace-events
@@ -195,6 +195,7 @@ disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d
 disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
 disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
 disable usb_set_addr(int addr) "dev %d"
+disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
 
 # vl.c
 disable vm_state_notify(int running, int reason) "running %d reason %d"
