Index: /trunk/src/VBox/Devices/Storage/UsbMsd.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/UsbMsd.cpp	(revision 43787)
+++ /trunk/src/VBox/Devices/Storage/UsbMsd.cpp	(revision 43788)
@@ -39,13 +39,21 @@
  * @{ */
 #define USBMSD_STR_ID_MANUFACTURER  1
-#define USBMSD_STR_ID_PRODUCT       2
+#define USBMSD_STR_ID_PRODUCT_HD    2
 /** @} */
 
+/** @name USB MSD vendor and product IDs
+ * @{ */
+#define VBOX_USB_VENDOR             0x80EE
+#define USBMSD_PID_HD               0x0030
+#define USBMSD_PID_CD               0x0031
+/** @} */
 
 /*******************************************************************************
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
-/**
- * USB Command block wrapper (MSD/SCSI).
+
+/**
+ * USB MSD Command Block Wrapper or CBW. The command block 
+ * itself (CBWCB) contains protocol-specific data (here SCSI).
  */
 #pragma pack(1)
@@ -72,5 +80,5 @@
 
 /**
- * USB Command Status Wrapper (MSD/SCSI).
+ * USB MSD Command Status Wrapper or CSW.
  */
 #pragma pack(1)
@@ -255,6 +263,6 @@
 static const PDMUSBDESCCACHESTRING g_aUsbMsdStrings_en_US[] =
 {
-    { USBMSD_STR_ID_MANUFACTURER,   "VirtualBox"     },
-    { USBMSD_STR_ID_PRODUCT,        "VirtualBox MSD" },
+    { USBMSD_STR_ID_MANUFACTURER,   "VirtualBox"   },
+    { USBMSD_STR_ID_PRODUCT_HD,     "USB Harddisk" },
 };
 
@@ -272,6 +280,6 @@
             /* .bEndpointAddress = */   0x81 /* ep=1, in */,
             /* .bmAttributes = */       2 /* bulk */,
-            /* .wMaxPacketSize = */     0x200 /* or 64? */,
-            /* .bInterval = */          0xff,
+            /* .wMaxPacketSize = */     64,//512 /* or 64? */,  <-- depends on device speed!
+            /* .bInterval = */          0,
         },
         /* .pvMore = */     NULL,
@@ -285,6 +293,6 @@
             /* .bEndpointAddress = */   0x02 /* ep=2, out */,
             /* .bmAttributes = */       2 /* bulk */,
-            /* .wMaxPacketSize = */     0x200 /* or 64? */,
-            /* .bInterval = */          0xff,
+            /* .wMaxPacketSize = */     64,//512 /* or 64? */,  <-- depends on device speed!
+            /* .bInterval = */          0,
         },
         /* .pvMore = */     NULL,
@@ -313,5 +321,5 @@
 };
 
-static const VUSBINTERFACE g_aUsbMsdInterfaces[2] =
+static const VUSBINTERFACE g_aUsbMsdInterfaces[] =
 {
     { &g_UsbMsdInterfaceDesc, /* .cSettings = */ 1 },
@@ -330,6 +338,7 @@
         /* .MaxPower = */           50 /* 100mA */
     },
-    NULL,
-    &g_aUsbMsdInterfaces[0]
+    NULL,                           /* pvMore */
+    &g_aUsbMsdInterfaces[0],
+    NULL                            /* pvOriginal */
 };
 
@@ -338,16 +347,29 @@
     /* .bLength = */                sizeof(g_UsbMsdDeviceDesc),
     /* .bDescriptorType = */        VUSB_DT_DEVICE,
-    /* .bcdUsb = */                 0x200,
+    /* .bcdUsb = */                 0x200, /* USB 2.0 */
     /* .bDeviceClass = */           0 /* Class specified in the interface desc. */,
     /* .bDeviceSubClass = */        0 /* Subclass specified in the interface desc. */,
-    /* .bDeviceProtocol = */        0x50 /* Protocol specified in the interface desc. */,
+    /* .bDeviceProtocol = */        0 /* Protocol specified in the interface desc. */,
     /* .bMaxPacketSize0 = */        64,
-    /* .idVendor = */               0x4200,
-    /* .idProduct = */              0x0042,
-    /* .bcdDevice = */              0x0100,
+    /* .idVendor = */               VBOX_USB_VENDOR,
+    /* .idProduct = */              USBMSD_PID_HD,
+    /* .bcdDevice = */              0x0100, /* 1.0 */
     /* .iManufacturer = */          USBMSD_STR_ID_MANUFACTURER,
-    /* .iProduct = */               USBMSD_STR_ID_PRODUCT,
+    /* .iProduct = */               USBMSD_STR_ID_PRODUCT_HD,
     /* .iSerialNumber = */          0,
     /* .bNumConfigurations = */     1
+};
+
+static const VUSBDEVICEQUALIFIER g_UsbMsdDeviceQualifier =
+{
+    /* .bLength = */                sizeof(g_UsbMsdDeviceQualifier),
+    /* .bDescriptorType = */        VUSB_DT_DEVICE_QUALIFIER,
+    /* .bcdUsb = */                 0x200, /* USB 2.0 */
+    /* .bDeviceClass = */           0 /* Class specified in the interface desc. */,
+    /* .bDeviceSubClass = */        0 /* Subclass specified in the interface desc. */,
+    /* .bDeviceProtocol = */        0 /* Protocol specified in the interface desc. */,
+    /* .bMaxPacketSize0 = */        64,
+    /* .bNumConfigurations = */     1,
+    /* .bReserved = */              0
 };
 
@@ -636,5 +658,5 @@
 
     pUrb->enmStatus = VUSBSTATUS_OK;
-    pUrb->cbData    = cbData;
+    pUrb->cbData    = (uint32_t)cbData;
 
     usbMsdLinkDone(pThis, pUrb);
@@ -665,5 +687,5 @@
         && pReq->enmState == USBMSDREQSTATE_EXECUTING)
     {
-        /* Don't try deal with the set config variant nor multiple build-only
+        /* Don't try to deal with the set config variant nor multiple build-only
            mass storage resets. */
         if (pThis->pResetUrb && (pUrb || fSetConfig))
@@ -785,5 +807,5 @@
                 break;
 
-            /* Process it as the normal way. */
+            /* Process it the normal way. */
             usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
         }
@@ -914,5 +936,5 @@
     if ((pCbw->bmCBWFlags & USBCBW_DIR_MASK) != USBCBW_DIR_IN)
         return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "direction");
-    if (pCbw->bCBWCBLength != 6)
+    if (pCbw->bCBWCBLength < 6)
         return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "length");
     if ((pCbw->CBWCB[1] >> 5) != pCbw->bCBWLun)
@@ -920,5 +942,5 @@
     if (pCbw->bCBWLun != 0)
         return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "lun0");
-    if ((pCbw->CBWCB[4] < 6) != pCbw->bCBWLun)
+    if (pCbw->CBWCB[4] < 6)
         return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "out length");
 
@@ -1001,5 +1023,5 @@
 
 /**
- * Handles request sent to the out-bound (to device) bulk pipe.
+ * Handle requests sent to the outbound (to device) bulk pipe.
  */
 static int usbMsdHandleBulkHostToDev(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
@@ -1035,6 +1057,4 @@
                 return usbMsdCompleteStall(pThis, NULL, pUrb, "BAD CBW");
             }
-            Log(("usbMsd: CBW: dCBWSignature=%#x dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x  cbData=%#x fShortNotOk=%RTbool\n",
-                 pCbw->dCBWSignature, pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
             if (pCbw->dCBWSignature != USBCBW_SIGNATURE)
             {
@@ -1042,4 +1062,6 @@
                 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
             }
+            Log(("usbMsd: CBW: dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x  cbData=%#x fShortNotOk=%RTbool\n",
+                 pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
             if (pCbw->bmCBWFlags & ~USBCBW_DIR_MASK)
             {
@@ -1149,5 +1171,5 @@
                 }
             }
-            return usbMsdCompleteOk(pThis, pUrb, 0);
+            return usbMsdCompleteOk(pThis, pUrb, cbData);
         }
 
@@ -1169,5 +1191,5 @@
 
 /**
- * Handles request sent to the in-bound (to host) bulk pipe.
+ * Handle requests sent to the inbound (to host) bulk pipe.
  */
 static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
@@ -1217,8 +1239,7 @@
         case USBMSDREQSTATE_STATUS:
         {
-            /** @todo !fShortNotOk and CSW request? */
-            if (pUrb->cbData != sizeof(USBCSW))
-            {
-                Log(("usbMsd: Unexpected status request size: %#x (expected %#x)\n", pUrb->cbData, sizeof(USBCSW)));
+            if ((pUrb->cbData < sizeof(USBCSW)) || (pUrb->cbData > sizeof(USBCSW) && pUrb->fShortNotOk))
+            {
+                Log(("usbMsd: Unexpected status request size: %#x (expected %#x), fShortNotOK=%RTbool\n", pUrb->cbData, sizeof(USBCSW), pUrb->fShortNotOk));
                 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
             }
@@ -1233,4 +1254,6 @@
                                 ? USBCSW_STATUS_FAILED
                                 : USBCSW_STATUS_PHASE_ERROR;
+            /** @todo the following is not always accurate; VSCSI needs
+             *        to implement residual counts properly! */
             if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
                 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
@@ -1239,7 +1262,7 @@
             else
                 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
-                                      ? pReq->ScsiReq.cbScatterGather
-                                      : 0;
-            Log(("usbMsdHandleBulkDevToHost: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
+                                      ? 0
+                                      : pReq->ScsiReq.cbScatterGather;
+            Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
                  pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
 
@@ -1334,7 +1357,16 @@
                 switch (pSetup->wValue >> 8)
                 {
+                    uint32_t    cbCopy;
+
                     case VUSB_DT_STRING:
                         Log(("usbMsd: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
                         break;
+                    case VUSB_DT_DEVICE_QUALIFIER:
+                        Log(("usbMsd: GET_DESCRIPTOR DT_DEVICE_QUALIFIER wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
+                        /* Returned data is written after the setup message. */
+                        cbCopy = pUrb->cbData - sizeof(*pSetup);
+                        cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdDeviceQualifier));
+                        memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdDeviceQualifier, cbCopy);
+                        return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
                     default:
                         Log(("usbMsd: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
