VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/UsbMsd.cpp@ 65648

Last change on this file since 65648 was 65648, checked in by vboxsync, 8 years ago

gcc 7: Devices: fall thru

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.3 KB
Line 
1/* $Id: UsbMsd.cpp 65648 2017-02-07 11:43:22Z vboxsync $ */
2/** @file
3 * UsbMSD - USB Mass Storage Device Emulation.
4 */
5
6/*
7 * Copyright (C) 2007-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_USB_MSD
23#include <VBox/vmm/pdmusb.h>
24#include <VBox/vmm/pdmstorageifs.h>
25#include <VBox/log.h>
26#include <VBox/err.h>
27#include <VBox/scsi.h>
28#include <iprt/assert.h>
29#include <iprt/critsect.h>
30#include <iprt/mem.h>
31#include <iprt/semaphore.h>
32#include <iprt/string.h>
33#include <iprt/uuid.h>
34#include "VBoxDD.h"
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40/** @name USB MSD string IDs
41 * @{ */
42#define USBMSD_STR_ID_MANUFACTURER 1
43#define USBMSD_STR_ID_PRODUCT_HD 2
44#define USBMSD_STR_ID_PRODUCT_CDROM 3
45/** @} */
46
47/** @name USB MSD vendor and product IDs
48 * @{ */
49#define VBOX_USB_VENDOR 0x80EE
50#define USBMSD_PID_HD 0x0030
51#define USBMSD_PID_CD 0x0031
52/** @} */
53
54/** Saved state version. */
55#define USB_MSD_SAVED_STATE_VERSION 2
56/** Saved state vesion before the cleanup. */
57#define USB_MSD_SAVED_STATE_VERSION_PRE_CLEANUP 1
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63
64/**
65 * USB MSD Command Block Wrapper or CBW. The command block
66 * itself (CBWCB) contains protocol-specific data (here SCSI).
67 */
68#pragma pack(1)
69typedef struct USBCBW
70{
71 uint32_t dCBWSignature;
72#define USBCBW_SIGNATURE UINT32_C(0x43425355)
73 uint32_t dCBWTag;
74 uint32_t dCBWDataTransferLength;
75 uint8_t bmCBWFlags;
76#define USBCBW_DIR_MASK RT_BIT(7)
77#define USBCBW_DIR_OUT 0
78#define USBCBW_DIR_IN RT_BIT(7)
79 uint8_t bCBWLun;
80 uint8_t bCBWCBLength;
81 uint8_t CBWCB[16];
82} USBCBW;
83#pragma pack()
84AssertCompileSize(USBCBW, 31);
85/** Pointer to a Command Block Wrapper. */
86typedef USBCBW *PUSBCBW;
87/** Pointer to a const Command Block Wrapper. */
88typedef const USBCBW *PCUSBCBW;
89
90/**
91 * USB MSD Command Status Wrapper or CSW.
92 */
93#pragma pack(1)
94typedef struct USBCSW
95{
96 uint32_t dCSWSignature;
97#define USBCSW_SIGNATURE UINT32_C(0x53425355)
98 uint32_t dCSWTag;
99 uint32_t dCSWDataResidue;
100#define USBCSW_STATUS_OK UINT8_C(0)
101#define USBCSW_STATUS_FAILED UINT8_C(1)
102#define USBCSW_STATUS_PHASE_ERROR UINT8_C(2)
103 uint8_t bCSWStatus;
104} USBCSW;
105#pragma pack()
106AssertCompileSize(USBCSW, 13);
107/** Pointer to a Command Status Wrapper. */
108typedef USBCSW *PUSBCSW;
109/** Pointer to a const Command Status Wrapper. */
110typedef const USBCSW *PCUSBCSW;
111
112
113/**
114 * The USB MSD request state.
115 */
116typedef enum USBMSDREQSTATE
117{
118 /** Invalid status. */
119 USBMSDREQSTATE_INVALID = 0,
120 /** Ready to receive a new SCSI command. */
121 USBMSDREQSTATE_READY,
122 /** Waiting for the host to supply data. */
123 USBMSDREQSTATE_DATA_FROM_HOST,
124 /** The SCSI request is being executed by the driver. */
125 USBMSDREQSTATE_EXECUTING,
126 /** Have (more) data for the host. */
127 USBMSDREQSTATE_DATA_TO_HOST,
128 /** Waiting to supply status information to the host. */
129 USBMSDREQSTATE_STATUS,
130 /** Destroy the request upon completion.
131 * This is set when the SCSI request doesn't complete before for the device or
132 * mass storage reset operation times out. USBMSD::pReq will be set to NULL
133 * and the only reference to this request will be with DrvSCSI. */
134 USBMSDREQSTATE_DESTROY_ON_COMPLETION,
135 /** The end of the valid states. */
136 USBMSDREQSTATE_END,
137 /** 32bit blow up hack. */
138 USBMSDREQSTATE_32BIT_HACK = 0x7fffffff
139} USBMSDREQSTATE;
140
141
142/**
143 * A pending USB MSD request.
144 */
145typedef struct USBMSDREQ
146{
147 /** The state of the request. */
148 USBMSDREQSTATE enmState;
149 /** The I/O requesthandle .*/
150 PDMMEDIAEXIOREQ hIoReq;
151 /** The size of the data buffer. */
152 uint32_t cbBuf;
153 /** Pointer to the data buffer. */
154 uint8_t *pbBuf;
155 /** Current buffer offset. */
156 uint32_t offBuf;
157 /** The current Cbw when we're in the pending state. */
158 USBCBW Cbw;
159 /** The status of a completed SCSI request. */
160 uint8_t iScsiReqStatus;
161} USBMSDREQ;
162/** Pointer to a USB MSD request. */
163typedef USBMSDREQ *PUSBMSDREQ;
164
165
166/**
167 * Endpoint status data.
168 */
169typedef struct USBMSDEP
170{
171 bool fHalted;
172} USBMSDEP;
173/** Pointer to the endpoint status. */
174typedef USBMSDEP *PUSBMSDEP;
175
176
177/**
178 * A URB queue.
179 */
180typedef struct USBMSDURBQUEUE
181{
182 /** The head pointer. */
183 PVUSBURB pHead;
184 /** Where to insert the next entry. */
185 PVUSBURB *ppTail;
186} USBMSDURBQUEUE;
187/** Pointer to a URB queue. */
188typedef USBMSDURBQUEUE *PUSBMSDURBQUEUE;
189/** Pointer to a const URB queue. */
190typedef USBMSDURBQUEUE const *PCUSBMSDURBQUEUE;
191
192
193/**
194 * The USB MSD instance data.
195 */
196typedef struct USBMSD
197{
198 /** Pointer back to the PDM USB Device instance structure. */
199 PPDMUSBINS pUsbIns;
200 /** Critical section protecting the device state. */
201 RTCRITSECT CritSect;
202
203 /** The current configuration.
204 * (0 - default, 1 - the only, i.e configured.) */
205 uint8_t bConfigurationValue;
206 /** Endpoint 0 is the default control pipe, 1 is the host->dev bulk pipe and 2
207 * is the dev->host one. */
208 USBMSDEP aEps[3];
209 /** The current request. */
210 PUSBMSDREQ pReq;
211
212 /** Pending to-host queue.
213 * The URBs waiting here are pending the completion of the current request and
214 * data or status to become available.
215 */
216 USBMSDURBQUEUE ToHostQueue;
217
218 /** Done queue
219 * The URBs stashed here are waiting to be reaped. */
220 USBMSDURBQUEUE DoneQueue;
221 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
222 * is set. */
223 RTSEMEVENT hEvtDoneQueue;
224 /** Someone is waiting on the done queue. */
225 bool fHaveDoneQueueWaiter;
226
227 /** Whether to signal the reset semaphore when the current request completes. */
228 bool fSignalResetSem;
229 /** Semaphore usbMsdUsbReset waits on when a request is executing at reset
230 * time. Only signalled when fSignalResetSem is set. */
231 RTSEMEVENTMULTI hEvtReset;
232 /** The reset URB.
233 * This is waiting for SCSI request completion before finishing the reset. */
234 PVUSBURB pResetUrb;
235 /** Indicates that PDMUsbHlpAsyncNotificationCompleted should be called when
236 * the MSD is entering the idle state. */
237 volatile bool fSignalIdle;
238
239 /** Indicates that this device is a CD-ROM. */
240 bool fIsCdrom;
241
242 /**
243 * LUN\#0 data.
244 */
245 struct
246 {
247 /** The base interface for LUN\#0. */
248 PDMIBASE IBase;
249 /** The media port interface fo LUN\#0. */
250 PDMIMEDIAPORT IMediaPort;
251 /** The extended media port interface for LUN\#0 */
252 PDMIMEDIAEXPORT IMediaExPort;
253
254 /** The base interface for the SCSI driver connected to LUN\#0. */
255 PPDMIBASE pIBase;
256 /** The media interface for th SCSI drver conected to LUN\#0. */
257 PPDMIMEDIA pIMedia;
258 /** The extended media inerface for the SCSI driver connected to LUN\#0. */
259 PPDMIMEDIAEX pIMediaEx;
260 } Lun0;
261
262} USBMSD;
263/** Pointer to the USB MSD instance data. */
264typedef USBMSD *PUSBMSD;
265
266
267/*********************************************************************************************************************************
268* Global Variables *
269*********************************************************************************************************************************/
270static const PDMUSBDESCCACHESTRING g_aUsbMsdStrings_en_US[] =
271{
272 { USBMSD_STR_ID_MANUFACTURER, "VirtualBox" },
273 { USBMSD_STR_ID_PRODUCT_HD, "USB Harddisk" },
274 { USBMSD_STR_ID_PRODUCT_CDROM, "USB CD-ROM" }
275};
276
277static const PDMUSBDESCCACHELANG g_aUsbMsdLanguages[] =
278{
279 { 0x0409, RT_ELEMENTS(g_aUsbMsdStrings_en_US), g_aUsbMsdStrings_en_US }
280};
281
282static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsFS[2] =
283{
284 {
285 {
286 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
287 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
288 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
289 /* .bmAttributes = */ 2 /* bulk */,
290 /* .wMaxPacketSize = */ 64 /* maximum possible */,
291 /* .bInterval = */ 0 /* not applicable for bulk EP */
292 },
293 /* .pvMore = */ NULL,
294 /* .pvClass = */ NULL,
295 /* .cbClass = */ 0,
296 /* .pvSsepc = */ NULL,
297 /* .cbSsepc = */ 0
298 },
299 {
300 {
301 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
302 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
303 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
304 /* .bmAttributes = */ 2 /* bulk */,
305 /* .wMaxPacketSize = */ 64 /* maximum possible */,
306 /* .bInterval = */ 0 /* not applicable for bulk EP */
307 },
308 /* .pvMore = */ NULL,
309 /* .pvClass = */ NULL,
310 /* .cbClass = */ 0,
311 /* .pvSsepc = */ NULL,
312 /* .cbSsepc = */ 0
313 }
314};
315
316static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsHS[2] =
317{
318 {
319 {
320 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
321 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
322 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
323 /* .bmAttributes = */ 2 /* bulk */,
324 /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
325 /* .bInterval = */ 0 /* no NAKs */
326 },
327 /* .pvMore = */ NULL,
328 /* .pvClass = */ NULL,
329 /* .cbClass = */ 0,
330 /* .pvSsepc = */ NULL,
331 /* .cbSsepc = */ 0
332 },
333 {
334 {
335 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
336 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
337 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
338 /* .bmAttributes = */ 2 /* bulk */,
339 /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
340 /* .bInterval = */ 0 /* no NAKs */
341 },
342 /* .pvMore = */ NULL,
343 /* .pvClass = */ NULL,
344 /* .cbClass = */ 0,
345 /* .pvSsepc = */ NULL,
346 /* .cbSsepc = */ 0
347 }
348};
349
350static const VUSBDESCSSEPCOMPANION g_aUsbMsdEpCompanionSS =
351{
352 /* .bLength = */ sizeof(VUSBDESCSSEPCOMPANION),
353 /* .bDescriptorType = */ VUSB_DT_SS_ENDPOINT_COMPANION,
354 /* .bMaxBurst = */ 15 /* we can burst all the way */,
355 /* .bmAttributes = */ 0 /* no streams */,
356 /* .wBytesPerInterval = */ 0 /* not a periodic endpoint */
357};
358
359static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsSS[2] =
360{
361 {
362 {
363 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
364 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
365 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
366 /* .bmAttributes = */ 2 /* bulk */,
367 /* .wMaxPacketSize = */ 1024 /* SS bulk packet size */,
368 /* .bInterval = */ 0 /* no NAKs */
369 },
370 /* .pvMore = */ NULL,
371 /* .pvClass = */ NULL,
372 /* .cbClass = */ 0,
373 /* .pvSsepc = */ &g_aUsbMsdEpCompanionSS,
374 /* .cbSsepc = */ sizeof(g_aUsbMsdEpCompanionSS)
375 },
376 {
377 {
378 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
379 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
380 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
381 /* .bmAttributes = */ 2 /* bulk */,
382 /* .wMaxPacketSize = */ 1024 /* SS bulk packet size */,
383 /* .bInterval = */ 0 /* no NAKs */
384 },
385 /* .pvMore = */ NULL,
386 /* .pvClass = */ NULL,
387 /* .cbClass = */ 0,
388 /* .pvSsepc = */ &g_aUsbMsdEpCompanionSS,
389 /* .cbSsepc = */ sizeof(g_aUsbMsdEpCompanionSS)
390 }
391};
392
393static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescFS =
394{
395 {
396 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
397 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
398 /* .bInterfaceNumber = */ 0,
399 /* .bAlternateSetting = */ 0,
400 /* .bNumEndpoints = */ 2,
401 /* .bInterfaceClass = */ 8 /* Mass Storage */,
402 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
403 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
404 /* .iInterface = */ 0
405 },
406 /* .pvMore = */ NULL,
407 /* .pvClass = */ NULL,
408 /* .cbClass = */ 0,
409 &g_aUsbMsdEndpointDescsFS[0],
410 /* .pIAD = */ NULL,
411 /* .cbIAD = */ 0
412};
413
414static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescHS =
415{
416 {
417 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
418 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
419 /* .bInterfaceNumber = */ 0,
420 /* .bAlternateSetting = */ 0,
421 /* .bNumEndpoints = */ 2,
422 /* .bInterfaceClass = */ 8 /* Mass Storage */,
423 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
424 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
425 /* .iInterface = */ 0
426 },
427 /* .pvMore = */ NULL,
428 /* .pvClass = */ NULL,
429 /* .cbClass = */ 0,
430 &g_aUsbMsdEndpointDescsHS[0],
431 /* .pIAD = */ NULL,
432 /* .cbIAD = */ 0
433};
434
435static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescSS =
436{
437 {
438 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
439 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
440 /* .bInterfaceNumber = */ 0,
441 /* .bAlternateSetting = */ 0,
442 /* .bNumEndpoints = */ 2,
443 /* .bInterfaceClass = */ 8 /* Mass Storage */,
444 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
445 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
446 /* .iInterface = */ 0
447 },
448 /* .pvMore = */ NULL,
449 /* .pvClass = */ NULL,
450 /* .cbClass = */ 0,
451 &g_aUsbMsdEndpointDescsSS[0],
452 /* .pIAD = */ NULL,
453 /* .cbIAD = */ 0
454};
455
456static const VUSBINTERFACE g_aUsbMsdInterfacesFS[] =
457{
458 { &g_UsbMsdInterfaceDescFS, /* .cSettings = */ 1 },
459};
460
461static const VUSBINTERFACE g_aUsbMsdInterfacesHS[] =
462{
463 { &g_UsbMsdInterfaceDescHS, /* .cSettings = */ 1 },
464};
465
466static const VUSBINTERFACE g_aUsbMsdInterfacesSS[] =
467{
468 { &g_UsbMsdInterfaceDescSS, /* .cSettings = */ 1 },
469};
470
471static const VUSBDESCCONFIGEX g_UsbMsdConfigDescFS =
472{
473 {
474 /* .bLength = */ sizeof(VUSBDESCCONFIG),
475 /* .bDescriptorType = */ VUSB_DT_CONFIG,
476 /* .wTotalLength = */ 0 /* recalculated on read */,
477 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesFS),
478 /* .bConfigurationValue =*/ 1,
479 /* .iConfiguration = */ 0,
480 /* .bmAttributes = */ RT_BIT(7),
481 /* .MaxPower = */ 50 /* 100mA */
482 },
483 NULL, /* pvMore */
484 &g_aUsbMsdInterfacesFS[0],
485 NULL /* pvOriginal */
486};
487
488static const VUSBDESCCONFIGEX g_UsbMsdConfigDescHS =
489{
490 {
491 /* .bLength = */ sizeof(VUSBDESCCONFIG),
492 /* .bDescriptorType = */ VUSB_DT_CONFIG,
493 /* .wTotalLength = */ 0 /* recalculated on read */,
494 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesHS),
495 /* .bConfigurationValue =*/ 1,
496 /* .iConfiguration = */ 0,
497 /* .bmAttributes = */ RT_BIT(7),
498 /* .MaxPower = */ 50 /* 100mA */
499 },
500 NULL, /* pvMore */
501 &g_aUsbMsdInterfacesHS[0],
502 NULL /* pvOriginal */
503};
504
505static const VUSBDESCCONFIGEX g_UsbMsdConfigDescSS =
506{
507 {
508 /* .bLength = */ sizeof(VUSBDESCCONFIG),
509 /* .bDescriptorType = */ VUSB_DT_CONFIG,
510 /* .wTotalLength = */ 0 /* recalculated on read */,
511 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesSS),
512 /* .bConfigurationValue =*/ 1,
513 /* .iConfiguration = */ 0,
514 /* .bmAttributes = */ RT_BIT(7),
515 /* .MaxPower = */ 50 /* 100mA */
516 },
517 NULL, /* pvMore */
518 &g_aUsbMsdInterfacesSS[0],
519 NULL /* pvOriginal */
520};
521
522static const VUSBDESCDEVICE g_UsbMsdDeviceDesc20 =
523{
524 /* .bLength = */ sizeof(g_UsbMsdDeviceDesc20),
525 /* .bDescriptorType = */ VUSB_DT_DEVICE,
526 /* .bcdUsb = */ 0x200, /* USB 2.0 */
527 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
528 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
529 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
530 /* .bMaxPacketSize0 = */ 64,
531 /* .idVendor = */ VBOX_USB_VENDOR,
532 /* .idProduct = */ USBMSD_PID_HD,
533 /* .bcdDevice = */ 0x0100, /* 1.0 */
534 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
535 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_HD,
536 /* .iSerialNumber = */ 0,
537 /* .bNumConfigurations = */ 1
538};
539
540static const VUSBDESCDEVICE g_UsbCdDeviceDesc20 =
541{
542 /* .bLength = */ sizeof(g_UsbCdDeviceDesc20),
543 /* .bDescriptorType = */ VUSB_DT_DEVICE,
544 /* .bcdUsb = */ 0x200, /* USB 2.0 */
545 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
546 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
547 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
548 /* .bMaxPacketSize0 = */ 64,
549 /* .idVendor = */ VBOX_USB_VENDOR,
550 /* .idProduct = */ USBMSD_PID_CD,
551 /* .bcdDevice = */ 0x0100, /* 1.0 */
552 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
553 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_CDROM,
554 /* .iSerialNumber = */ 0,
555 /* .bNumConfigurations = */ 1
556};
557
558static const VUSBDESCDEVICE g_UsbMsdDeviceDesc30 =
559{
560 /* .bLength = */ sizeof(g_UsbMsdDeviceDesc30),
561 /* .bDescriptorType = */ VUSB_DT_DEVICE,
562 /* .bcdUsb = */ 0x300, /* USB 2.0 */
563 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
564 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
565 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
566 /* .bMaxPacketSize0 = */ 9 /* 512, the only option for USB3. */,
567 /* .idVendor = */ VBOX_USB_VENDOR,
568 /* .idProduct = */ USBMSD_PID_HD,
569 /* .bcdDevice = */ 0x0110, /* 1.10 */
570 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
571 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_HD,
572 /* .iSerialNumber = */ 0,
573 /* .bNumConfigurations = */ 1
574};
575
576static const VUSBDESCDEVICE g_UsbCdDeviceDesc30 =
577{
578 /* .bLength = */ sizeof(g_UsbCdDeviceDesc30),
579 /* .bDescriptorType = */ VUSB_DT_DEVICE,
580 /* .bcdUsb = */ 0x300, /* USB 2.0 */
581 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
582 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
583 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
584 /* .bMaxPacketSize0 = */ 9 /* 512, the only option for USB3. */,
585 /* .idVendor = */ VBOX_USB_VENDOR,
586 /* .idProduct = */ USBMSD_PID_CD,
587 /* .bcdDevice = */ 0x0110, /* 1.10 */
588 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
589 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_CDROM,
590 /* .iSerialNumber = */ 0,
591 /* .bNumConfigurations = */ 1
592};
593
594static const VUSBDEVICEQUALIFIER g_UsbMsdDeviceQualifier =
595{
596 /* .bLength = */ sizeof(g_UsbMsdDeviceQualifier),
597 /* .bDescriptorType = */ VUSB_DT_DEVICE_QUALIFIER,
598 /* .bcdUsb = */ 0x200, /* USB 2.0 */
599 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
600 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
601 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
602 /* .bMaxPacketSize0 = */ 64,
603 /* .bNumConfigurations = */ 1,
604 /* .bReserved = */ 0
605};
606
607static const struct {
608 VUSBDESCBOS bos;
609 VUSBDESCSSDEVCAP sscap;
610} g_UsbMsdBOS =
611{
612 {
613 /* .bLength = */ sizeof(g_UsbMsdBOS.bos),
614 /* .bDescriptorType = */ VUSB_DT_BOS,
615 /* .wTotalLength = */ sizeof(g_UsbMsdBOS),
616 /* .bNumDeviceCaps = */ 1
617 },
618 {
619 /* .bLength = */ sizeof(VUSBDESCSSDEVCAP),
620 /* .bDescriptorType = */ VUSB_DT_DEVICE_CAPABILITY,
621 /* .bDevCapabilityType = */ VUSB_DCT_SUPERSPEED_USB,
622 /* .bmAttributes = */ 0 /* No LTM. */,
623 /* .wSpeedsSupported = */ 0xe /* Any speed is good. */,
624 /* .bFunctionalitySupport = */ 2 /* Want HS at least. */,
625 /* .bU1DevExitLat = */ 0, /* We are blazingly fast. */
626 /* .wU2DevExitLat = */ 0
627 }
628};
629
630static const PDMUSBDESCCACHE g_UsbMsdDescCacheFS =
631{
632 /* .pDevice = */ &g_UsbMsdDeviceDesc20,
633 /* .paConfigs = */ &g_UsbMsdConfigDescFS,
634 /* .paLanguages = */ g_aUsbMsdLanguages,
635 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
636 /* .fUseCachedDescriptors = */ true,
637 /* .fUseCachedStringsDescriptors = */ true
638};
639
640static const PDMUSBDESCCACHE g_UsbCdDescCacheFS =
641{
642 /* .pDevice = */ &g_UsbCdDeviceDesc20,
643 /* .paConfigs = */ &g_UsbMsdConfigDescFS,
644 /* .paLanguages = */ g_aUsbMsdLanguages,
645 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
646 /* .fUseCachedDescriptors = */ true,
647 /* .fUseCachedStringsDescriptors = */ true
648};
649
650static const PDMUSBDESCCACHE g_UsbMsdDescCacheHS =
651{
652 /* .pDevice = */ &g_UsbMsdDeviceDesc20,
653 /* .paConfigs = */ &g_UsbMsdConfigDescHS,
654 /* .paLanguages = */ g_aUsbMsdLanguages,
655 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
656 /* .fUseCachedDescriptors = */ true,
657 /* .fUseCachedStringsDescriptors = */ true
658};
659
660static const PDMUSBDESCCACHE g_UsbCdDescCacheHS =
661{
662 /* .pDevice = */ &g_UsbCdDeviceDesc20,
663 /* .paConfigs = */ &g_UsbMsdConfigDescHS,
664 /* .paLanguages = */ g_aUsbMsdLanguages,
665 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
666 /* .fUseCachedDescriptors = */ true,
667 /* .fUseCachedStringsDescriptors = */ true
668};
669
670static const PDMUSBDESCCACHE g_UsbMsdDescCacheSS =
671{
672 /* .pDevice = */ &g_UsbMsdDeviceDesc30,
673 /* .paConfigs = */ &g_UsbMsdConfigDescSS,
674 /* .paLanguages = */ g_aUsbMsdLanguages,
675 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
676 /* .fUseCachedDescriptors = */ true,
677 /* .fUseCachedStringsDescriptors = */ true
678};
679
680static const PDMUSBDESCCACHE g_UsbCdDescCacheSS =
681{
682 /* .pDevice = */ &g_UsbCdDeviceDesc30,
683 /* .paConfigs = */ &g_UsbMsdConfigDescSS,
684 /* .paLanguages = */ g_aUsbMsdLanguages,
685 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
686 /* .fUseCachedDescriptors = */ true,
687 /* .fUseCachedStringsDescriptors = */ true
688};
689
690
691/*********************************************************************************************************************************
692* Internal Functions *
693*********************************************************************************************************************************/
694static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb);
695
696
697/**
698 * Initializes an URB queue.
699 *
700 * @param pQueue The URB queue.
701 */
702static void usbMsdQueueInit(PUSBMSDURBQUEUE pQueue)
703{
704 pQueue->pHead = NULL;
705 pQueue->ppTail = &pQueue->pHead;
706}
707
708
709
710/**
711 * Inserts an URB at the end of the queue.
712 *
713 * @param pQueue The URB queue.
714 * @param pUrb The URB to insert.
715 */
716DECLINLINE(void) usbMsdQueueAddTail(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
717{
718 pUrb->Dev.pNext = NULL;
719 *pQueue->ppTail = pUrb;
720 pQueue->ppTail = &pUrb->Dev.pNext;
721}
722
723
724/**
725 * Unlinks the head of the queue and returns it.
726 *
727 * @returns The head entry.
728 * @param pQueue The URB queue.
729 */
730DECLINLINE(PVUSBURB) usbMsdQueueRemoveHead(PUSBMSDURBQUEUE pQueue)
731{
732 PVUSBURB pUrb = pQueue->pHead;
733 if (pUrb)
734 {
735 PVUSBURB pNext = pUrb->Dev.pNext;
736 pQueue->pHead = pNext;
737 if (!pNext)
738 pQueue->ppTail = &pQueue->pHead;
739 else
740 pUrb->Dev.pNext = NULL;
741 }
742 return pUrb;
743}
744
745
746/**
747 * Removes an URB from anywhere in the queue.
748 *
749 * @returns true if found, false if not.
750 * @param pQueue The URB queue.
751 * @param pUrb The URB to remove.
752 */
753DECLINLINE(bool) usbMsdQueueRemove(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
754{
755 PVUSBURB pCur = pQueue->pHead;
756 if (pCur == pUrb)
757 pQueue->pHead = pUrb->Dev.pNext;
758 else
759 {
760 while (pCur)
761 {
762 if (pCur->Dev.pNext == pUrb)
763 {
764 pCur->Dev.pNext = pUrb->Dev.pNext;
765 break;
766 }
767 pCur = pCur->Dev.pNext;
768 }
769 if (!pCur)
770 return false;
771 }
772 if (!pUrb->Dev.pNext)
773 pQueue->ppTail = &pQueue->pHead;
774 return true;
775}
776
777
778#ifdef VBOX_STRICT
779/**
780 * Checks if the queue is empty or not.
781 *
782 * @returns true if it is, false if it isn't.
783 * @param pQueue The URB queue.
784 */
785DECLINLINE(bool) usbMsdQueueIsEmpty(PCUSBMSDURBQUEUE pQueue)
786{
787 return pQueue->pHead == NULL;
788}
789#endif /* VBOX_STRICT */
790
791
792/**
793 * Links an URB into the done queue.
794 *
795 * @param pThis The MSD instance.
796 * @param pUrb The URB.
797 */
798static void usbMsdLinkDone(PUSBMSD pThis, PVUSBURB pUrb)
799{
800 usbMsdQueueAddTail(&pThis->DoneQueue, pUrb);
801
802 if (pThis->fHaveDoneQueueWaiter)
803 {
804 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
805 AssertRC(rc);
806 }
807}
808
809
810
811
812/**
813 * Allocates a new request and does basic init.
814 *
815 * @returns Pointer to the new request. NULL if we're out of memory.
816 * @param pThis The MSD instance.
817 */
818static PUSBMSDREQ usbMsdReqAlloc(PUSBMSD pThis)
819{
820 PUSBMSDREQ pReq = NULL;
821 PDMMEDIAEXIOREQ hIoReq = NULL;
822
823 int rc = pThis->Lun0.pIMediaEx->pfnIoReqAlloc(pThis->Lun0.pIMediaEx, &hIoReq, (void **)&pReq,
824 0 /* uTag */, PDMIMEDIAEX_F_DEFAULT);
825 if (RT_SUCCESS(rc))
826 {
827 pReq->hIoReq = hIoReq;
828 pReq->enmState = USBMSDREQSTATE_READY;
829 pReq->iScsiReqStatus = 0xff;
830 }
831 else
832 LogRel(("usbMsdReqAlloc: Out of memory (%Rrc)\n", rc));
833
834 return pReq;
835}
836
837
838/**
839 * Frees a request.
840 *
841 * @param pThis The MSD instance.
842 * @param pReq The request.
843 */
844static void usbMsdReqFree(PUSBMSD pThis, PUSBMSDREQ pReq)
845{
846 /*
847 * Check the input.
848 */
849 AssertReturnVoid( pReq->enmState > USBMSDREQSTATE_INVALID
850 && pReq->enmState != USBMSDREQSTATE_EXECUTING
851 && pReq->enmState < USBMSDREQSTATE_END);
852 PPDMUSBINS pUsbIns = pThis->pUsbIns;
853 AssertPtrReturnVoid(pUsbIns);
854 AssertReturnVoid(PDM_VERSION_ARE_COMPATIBLE(pUsbIns->u32Version, PDM_USBINS_VERSION));
855
856 /*
857 * Invalidate it and free the associated resources.
858 */
859 pReq->enmState = USBMSDREQSTATE_INVALID;
860 pReq->cbBuf = 0;
861 pReq->offBuf = 0;
862
863 if (pReq->pbBuf)
864 {
865 PDMUsbHlpMMHeapFree(pUsbIns, pReq->pbBuf);
866 pReq->pbBuf = NULL;
867 }
868
869 int rc = pThis->Lun0.pIMediaEx->pfnIoReqFree(pThis->Lun0.pIMediaEx, pReq->hIoReq);
870 AssertRC(rc);
871}
872
873
874/**
875 * Prepares a request for execution or data buffering.
876 *
877 * @param pReq The request.
878 * @param pCbw The SCSI command block wrapper.
879 */
880static void usbMsdReqPrepare(PUSBMSDREQ pReq, PCUSBCBW pCbw)
881{
882 /* Copy the CBW */
883 size_t cbCopy = RT_OFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]);
884 memcpy(&pReq->Cbw, pCbw, cbCopy);
885 memset((uint8_t *)&pReq->Cbw + cbCopy, 0, sizeof(pReq->Cbw) - cbCopy);
886
887 /* Setup the SCSI request. */
888 pReq->offBuf = 0;
889 pReq->iScsiReqStatus = 0xff;
890}
891
892
893/**
894 * Makes sure that there is sufficient buffer space available.
895 *
896 * @returns Success indicator (true/false)
897 * @param pThis The MSD instance.
898 * @param pReq The request.
899 * @param cbBuf The required buffer space.
900 */
901static int usbMsdReqEnsureBuffer(PUSBMSD pThis, PUSBMSDREQ pReq, uint32_t cbBuf)
902{
903 if (RT_LIKELY(pReq->cbBuf >= cbBuf))
904 RT_BZERO(pReq->pbBuf, cbBuf);
905 else
906 {
907 PDMUsbHlpMMHeapFree(pThis->pUsbIns, pReq->pbBuf);
908 pReq->cbBuf = 0;
909
910 cbBuf = RT_ALIGN_Z(cbBuf, 0x1000);
911 pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pThis->pUsbIns, cbBuf);
912 if (!pReq->pbBuf)
913 return false;
914
915 pReq->cbBuf = cbBuf;
916 }
917 return true;
918}
919
920
921/**
922 * Completes the URB with a stalled state, halting the pipe.
923 */
924static int usbMsdCompleteStall(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb, const char *pszWhy)
925{
926 RT_NOREF(pszWhy);
927 Log(("usbMsdCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
928
929 pUrb->enmStatus = VUSBSTATUS_STALL;
930
931 /** @todo figure out if the stall is global or pipe-specific or both. */
932 if (pEp)
933 pEp->fHalted = true;
934 else
935 {
936 pThis->aEps[1].fHalted = true;
937 pThis->aEps[2].fHalted = true;
938 }
939
940 usbMsdLinkDone(pThis, pUrb);
941 return VINF_SUCCESS;
942}
943
944
945/**
946 * Completes the URB with a OK state.
947 */
948static int usbMsdCompleteOk(PUSBMSD pThis, PVUSBURB pUrb, size_t cbData)
949{
950 Log(("usbMsdCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
951
952 pUrb->enmStatus = VUSBSTATUS_OK;
953 pUrb->cbData = (uint32_t)cbData;
954
955 usbMsdLinkDone(pThis, pUrb);
956 return VINF_SUCCESS;
957}
958
959
960/**
961 * Reset worker for usbMsdUsbReset, usbMsdUsbSetConfiguration and
962 * usbMsdUrbHandleDefaultPipe.
963 *
964 * @returns VBox status code.
965 * @param pThis The MSD instance.
966 * @param pUrb Set when usbMsdUrbHandleDefaultPipe is the
967 * caller.
968 * @param fSetConfig Set when usbMsdUsbSetConfiguration is the
969 * caller.
970 */
971static int usbMsdResetWorker(PUSBMSD pThis, PVUSBURB pUrb, bool fSetConfig)
972{
973 /*
974 * Wait for the any command currently executing to complete before
975 * resetting. (We cannot cancel its execution.) How we do this depends
976 * on the reset method.
977 */
978 PUSBMSDREQ pReq = pThis->pReq;
979 if ( pReq
980 && pReq->enmState == USBMSDREQSTATE_EXECUTING)
981 {
982 /* Don't try to deal with the set config variant nor multiple build-only
983 mass storage resets. */
984 if (pThis->pResetUrb && (pUrb || fSetConfig))
985 {
986 Log(("usbMsdResetWorker: pResetUrb is already %p:%s - stalling\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
987 return usbMsdCompleteStall(pThis, NULL, pUrb, "pResetUrb");
988 }
989
990 /* Bulk-Only Mass Storage Reset: Complete the reset on request completion. */
991 if (pUrb)
992 {
993 pThis->pResetUrb = pUrb;
994 Log(("usbMsdResetWorker: Setting pResetUrb to %p:%s\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
995 return VINF_SUCCESS;
996 }
997
998 /* Device reset: Wait for up to 10 ms. If it doesn't work, ditch
999 whole the request structure. We'll allocate a new one when needed. */
1000 Log(("usbMsdResetWorker: Waiting for completion...\n"));
1001 Assert(!pThis->fSignalResetSem);
1002 pThis->fSignalResetSem = true;
1003 RTSemEventMultiReset(pThis->hEvtReset);
1004 RTCritSectLeave(&pThis->CritSect);
1005
1006 int rc = RTSemEventMultiWait(pThis->hEvtReset, 10 /*ms*/);
1007
1008 RTCritSectEnter(&pThis->CritSect);
1009 pThis->fSignalResetSem = false;
1010 if ( RT_FAILURE(rc)
1011 || pReq->enmState == USBMSDREQSTATE_EXECUTING)
1012 {
1013 Log(("usbMsdResetWorker: Didn't complete, ditching the current request (%p)!\n", pReq));
1014 Assert(pReq == pThis->pReq);
1015 pReq->enmState = USBMSDREQSTATE_DESTROY_ON_COMPLETION;
1016 pThis->pReq = NULL;
1017 pReq = NULL;
1018 }
1019 }
1020
1021 /*
1022 * Reset the request and device state.
1023 */
1024 if (pReq)
1025 {
1026 pReq->enmState = USBMSDREQSTATE_READY;
1027 pReq->iScsiReqStatus = 0xff;
1028 }
1029
1030 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
1031 pThis->aEps[i].fHalted = false;
1032
1033 if (!pUrb && !fSetConfig) /* (only device reset) */
1034 pThis->bConfigurationValue = 0; /* default */
1035
1036 /*
1037 * Ditch all pending URBs.
1038 */
1039 PVUSBURB pCurUrb;
1040 while ((pCurUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
1041 {
1042 pCurUrb->enmStatus = VUSBSTATUS_CRC;
1043 usbMsdLinkDone(pThis, pCurUrb);
1044 }
1045
1046 pCurUrb = pThis->pResetUrb;
1047 if (pCurUrb)
1048 {
1049 pThis->pResetUrb = NULL;
1050 pCurUrb->enmStatus = VUSBSTATUS_CRC;
1051 usbMsdLinkDone(pThis, pCurUrb);
1052 }
1053
1054 if (pUrb)
1055 return usbMsdCompleteOk(pThis, pUrb, 0);
1056 return VINF_SUCCESS;
1057}
1058
1059
1060/**
1061 * Process a completed request.
1062 *
1063 * @returns nothing.
1064 * @param pThis The MSD instance.
1065 * @param pReq The request.
1066 * @param rcReq The completion status.
1067 */
1068static void usbMsdReqComplete(PUSBMSD pThis, PUSBMSDREQ pReq, int rcReq)
1069{
1070 RT_NOREF1(rcReq);
1071
1072 Log(("usbMsdLun0IoReqCompleteNotify: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, pReq->iScsiReqStatus));
1073 RTCritSectEnter(&pThis->CritSect);
1074
1075 if (pReq->enmState != USBMSDREQSTATE_DESTROY_ON_COMPLETION)
1076 {
1077 Assert(pReq->enmState == USBMSDREQSTATE_EXECUTING);
1078 Assert(pThis->pReq == pReq);
1079
1080 /*
1081 * Advance the state machine. The state machine is not affected by
1082 * SCSI errors.
1083 */
1084 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
1085 {
1086 pReq->enmState = USBMSDREQSTATE_STATUS;
1087 Log(("usbMsdLun0IoReqCompleteNotify: Entering STATUS\n"));
1088 }
1089 else
1090 {
1091 pReq->enmState = USBMSDREQSTATE_DATA_TO_HOST;
1092 Log(("usbMsdLun0IoReqCompleteNotify: Entering DATA_TO_HOST\n"));
1093 }
1094
1095 /*
1096 * Deal with pending to-host URBs.
1097 */
1098 for (;;)
1099 {
1100 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue);
1101 if (!pUrb)
1102 break;
1103
1104 /* Process it the normal way. */
1105 usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
1106 }
1107 }
1108 else
1109 {
1110 Log(("usbMsdLun0IoReqCompleteNotify: freeing %p\n", pReq));
1111 usbMsdReqFree(pThis, pReq);
1112 }
1113
1114 if (pThis->fSignalResetSem)
1115 RTSemEventMultiSignal(pThis->hEvtReset);
1116
1117 if (pThis->pResetUrb)
1118 {
1119 pThis->pResetUrb = NULL;
1120 usbMsdResetWorker(pThis, pThis->pResetUrb, false /*fSetConfig*/);
1121 }
1122
1123 RTCritSectLeave(&pThis->CritSect);
1124}
1125
1126
1127/**
1128 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
1129 */
1130static DECLCALLBACK(int) usbMsdLun0IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1131 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
1132 size_t cbCopy)
1133{
1134 RT_NOREF2(pInterface, hIoReq);
1135 int rc = VINF_SUCCESS;
1136 PUSBMSDREQ pReq = (PUSBMSDREQ)pvIoReqAlloc;
1137
1138 if (RT_UNLIKELY(offDst + cbCopy > pReq->cbBuf))
1139 rc = VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
1140 else
1141 {
1142 size_t cbCopied = RTSgBufCopyToBuf(pSgBuf, pReq->pbBuf + offDst, cbCopy);
1143 Assert(cbCopied == cbCopy); RT_NOREF(cbCopied);
1144 }
1145
1146 return rc;
1147}
1148
1149
1150/**
1151 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
1152 */
1153static DECLCALLBACK(int) usbMsdLun0IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1154 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
1155 size_t cbCopy)
1156{
1157 RT_NOREF2(pInterface, hIoReq);
1158 int rc = VINF_SUCCESS;
1159 PUSBMSDREQ pReq = (PUSBMSDREQ)pvIoReqAlloc;
1160
1161 if (RT_UNLIKELY(offSrc + cbCopy > pReq->cbBuf))
1162 rc = VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
1163 else
1164 {
1165 size_t cbCopied = RTSgBufCopyFromBuf(pSgBuf, pReq->pbBuf + offSrc, cbCopy);
1166 Assert(cbCopied == cbCopy); RT_NOREF(cbCopied);
1167 }
1168
1169 return rc;
1170}
1171
1172
1173/**
1174 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
1175 */
1176static DECLCALLBACK(int) usbMsdLun0IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1177 void *pvIoReqAlloc, int rcReq)
1178{
1179 RT_NOREF1(hIoReq);
1180 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IMediaExPort);
1181 PUSBMSDREQ pReq = (PUSBMSDREQ)pvIoReqAlloc;
1182
1183 usbMsdReqComplete(pThis, pReq, rcReq);
1184 return VINF_SUCCESS;
1185}
1186
1187
1188/**
1189 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
1190 */
1191static DECLCALLBACK(void) usbMsdLun0IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1192 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
1193{
1194 RT_NOREF4(pInterface, hIoReq, pvIoReqAlloc, enmState);
1195 AssertLogRelMsgFailed(("This should not be hit because I/O requests should not be suspended\n"));
1196}
1197
1198
1199/**
1200 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
1201 */
1202static DECLCALLBACK(void) usbMsdLun0MediumEjected(PPDMIMEDIAEXPORT pInterface)
1203{
1204 RT_NOREF1(pInterface); /** @todo */
1205}
1206
1207
1208/**
1209 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
1210 */
1211static DECLCALLBACK(int) usbMsdLun0QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
1212 uint32_t *piInstance, uint32_t *piLUN)
1213{
1214 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IMediaPort);
1215 PPDMUSBINS pUsbIns = pThis->pUsbIns;
1216
1217 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
1218 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
1219 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
1220
1221 *ppcszController = pUsbIns->pReg->szName;
1222 *piInstance = pUsbIns->iInstance;
1223 *piLUN = 0;
1224
1225 return VINF_SUCCESS;
1226}
1227
1228
1229/**
1230 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1231 */
1232static DECLCALLBACK(void *) usbMsdLun0QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1233{
1234 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IBase);
1235 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1236 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->Lun0.IMediaPort);
1237 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->Lun0.IMediaExPort);
1238 return NULL;
1239}
1240
1241
1242/**
1243 * Checks if all asynchronous I/O is finished.
1244 *
1245 * Used by usbMsdVMReset, usbMsdVMSuspend and usbMsdVMPowerOff.
1246 *
1247 * @returns true if quiesced, false if busy.
1248 * @param pUsbIns The USB device instance.
1249 */
1250static bool usbMsdAllAsyncIOIsFinished(PPDMUSBINS pUsbIns)
1251{
1252 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1253
1254 if ( VALID_PTR(pThis->pReq)
1255 && pThis->pReq->enmState == USBMSDREQSTATE_EXECUTING)
1256 return false;
1257
1258 return true;
1259}
1260
1261/**
1262 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
1263 * Callback employed by usbMsdVMSuspend and usbMsdVMPowerOff.}
1264 */
1265static DECLCALLBACK(bool) usbMsdIsAsyncSuspendOrPowerOffDone(PPDMUSBINS pUsbIns)
1266{
1267 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
1268 return false;
1269
1270 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1271 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
1272 return true;
1273}
1274
1275/**
1276 * Common worker for usbMsdVMSuspend and usbMsdVMPowerOff.
1277 */
1278static void usbMsdSuspendOrPowerOff(PPDMUSBINS pUsbIns)
1279{
1280 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1281
1282 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
1283 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
1284 PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncSuspendOrPowerOffDone);
1285 else
1286 {
1287 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
1288
1289 if (pThis->pReq)
1290 {
1291 usbMsdReqFree(pThis, pThis->pReq);
1292 pThis->pReq = NULL;
1293 }
1294 }
1295}
1296
1297
1298/* -=-=-=-=- Saved State -=-=-=-=- */
1299
1300/**
1301 * @callback_method_impl{FNSSMUSBSAVEPREP}
1302 */
1303static DECLCALLBACK(int) usbMsdSavePrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1304{
1305 RT_NOREF(pSSM);
1306#ifdef VBOX_STRICT
1307 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1308 Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
1309 Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
1310 Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
1311#else
1312 RT_NOREF(pUsbIns);
1313#endif
1314 return VINF_SUCCESS;
1315}
1316
1317/**
1318 * @callback_method_impl{FNSSMUSBLOADPREP}
1319 */
1320static DECLCALLBACK(int) usbMsdLoadPrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1321{
1322 RT_NOREF(pSSM);
1323#ifdef VBOX_STRICT
1324 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1325 Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
1326 Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
1327 Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
1328#else
1329 RT_NOREF(pUsbIns);
1330#endif
1331 return VINF_SUCCESS;
1332}
1333
1334/**
1335 * @callback_method_impl{FNSSMUSBLIVEEXEC}
1336 */
1337static DECLCALLBACK(int) usbMsdLiveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)
1338{
1339 RT_NOREF(uPass);
1340 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1341
1342 /* config. */
1343 SSMR3PutBool(pSSM, pThis->Lun0.pIBase != NULL);
1344 return VINF_SSM_DONT_CALL_AGAIN;
1345}
1346
1347/**
1348 * @callback_method_impl{FNSSMUSBSAVEEXEC}
1349 */
1350static DECLCALLBACK(int) usbMsdSaveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1351{
1352 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1353 int rc;
1354
1355 /* The config */
1356 rc = usbMsdLiveExec(pUsbIns, pSSM, SSM_PASS_FINAL);
1357 AssertRCReturn(rc, rc);
1358
1359 SSMR3PutU8(pSSM, pThis->bConfigurationValue);
1360 SSMR3PutBool(pSSM, pThis->aEps[0].fHalted);
1361 SSMR3PutBool(pSSM, pThis->aEps[1].fHalted);
1362 SSMR3PutBool(pSSM, pThis->aEps[2].fHalted);
1363 SSMR3PutBool(pSSM, pThis->pReq != NULL);
1364
1365 if (pThis->pReq)
1366 {
1367 PUSBMSDREQ pReq = pThis->pReq;
1368
1369 SSMR3PutU32(pSSM, pReq->enmState);
1370 SSMR3PutU32(pSSM, pReq->cbBuf);
1371 if (pReq->cbBuf)
1372 {
1373 AssertPtr(pReq->pbBuf);
1374 SSMR3PutMem(pSSM, pReq->pbBuf, pReq->cbBuf);
1375 }
1376
1377 SSMR3PutU32(pSSM, pReq->offBuf);
1378 SSMR3PutMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
1379 SSMR3PutU8(pSSM, pReq->iScsiReqStatus);
1380 }
1381
1382 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1383}
1384
1385/**
1386 * @callback_method_impl{FNSSMUSBLOADEXEC}
1387 */
1388static DECLCALLBACK(int) usbMsdLoadExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1389{
1390 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1391 uint32_t u32;
1392 int rc;
1393
1394 if (uVersion > USB_MSD_SAVED_STATE_VERSION)
1395 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1396
1397 /* Verify config. */
1398 bool fInUse;
1399 rc = SSMR3GetBool(pSSM, &fInUse);
1400 AssertRCReturn(rc, rc);
1401 if (fInUse != (pThis->Lun0.pIBase != NULL))
1402 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1403 N_("The %s VM is missing a USB mass storage device. Please make sure the source and target VMs have compatible storage configurations"),
1404 fInUse ? "target" : "source");
1405
1406 if (uPass == SSM_PASS_FINAL)
1407 {
1408 /* Restore data. */
1409 Assert(!pThis->pReq);
1410
1411 SSMR3GetU8(pSSM, &pThis->bConfigurationValue);
1412 SSMR3GetBool(pSSM, &pThis->aEps[0].fHalted);
1413 SSMR3GetBool(pSSM, &pThis->aEps[1].fHalted);
1414 SSMR3GetBool(pSSM, &pThis->aEps[2].fHalted);
1415 bool fReqAlloc = false;
1416 rc = SSMR3GetBool(pSSM, &fReqAlloc);
1417 AssertRCReturn(rc, rc);
1418 if (fReqAlloc)
1419 {
1420 PUSBMSDREQ pReq = usbMsdReqAlloc(pThis);
1421 AssertReturn(pReq, VERR_NO_MEMORY);
1422 pThis->pReq = pReq;
1423
1424 SSMR3GetU32(pSSM, (uint32_t *)&pReq->enmState);
1425 uint32_t cbBuf = 0;
1426 rc = SSMR3GetU32(pSSM, &cbBuf);
1427 AssertRCReturn(rc, rc);
1428 if (cbBuf)
1429 {
1430 if (usbMsdReqEnsureBuffer(pThis, pReq, cbBuf))
1431 {
1432 AssertPtr(pReq->pbBuf);
1433 Assert(cbBuf == pReq->cbBuf);
1434 SSMR3GetMem(pSSM, pReq->pbBuf, pReq->cbBuf);
1435 }
1436 else
1437 return VERR_NO_MEMORY;
1438 }
1439
1440 SSMR3GetU32(pSSM, &pReq->offBuf);
1441 SSMR3GetMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
1442
1443 if (uVersion >= USB_MSD_SAVED_STATE_VERSION_PRE_CLEANUP)
1444 rc = SSMR3GetU8(pSSM, &pReq->iScsiReqStatus);
1445 else
1446 {
1447 int32_t iScsiReqStatus;
1448
1449 /* Skip old fields which are unused now or can be determined from the CBW. */
1450 SSMR3Skip(pSSM, 4 * 4 + 64);
1451 rc = SSMR3GetS32(pSSM, &iScsiReqStatus);
1452 pReq->iScsiReqStatus = (uint8_t)iScsiReqStatus;
1453 }
1454 AssertRCReturn(rc, rc);
1455 }
1456
1457 rc = SSMR3GetU32(pSSM, &u32);
1458 AssertRCReturn(rc, rc);
1459 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1460 }
1461
1462 return VINF_SUCCESS;
1463}
1464
1465
1466/**
1467 * @interface_method_impl{PDMUSBREG,pfnUrbReap}
1468 */
1469static DECLCALLBACK(PVUSBURB) usbMsdUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1470{
1471 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1472 LogFlow(("usbMsdUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1473
1474 RTCritSectEnter(&pThis->CritSect);
1475
1476 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
1477 if (!pUrb && cMillies)
1478 {
1479 /* Wait */
1480 pThis->fHaveDoneQueueWaiter = true;
1481 RTCritSectLeave(&pThis->CritSect);
1482
1483 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1484
1485 RTCritSectEnter(&pThis->CritSect);
1486 pThis->fHaveDoneQueueWaiter = false;
1487
1488 pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
1489 }
1490
1491 RTCritSectLeave(&pThis->CritSect);
1492
1493 if (pUrb)
1494 Log(("usbMsdUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1495 return pUrb;
1496}
1497
1498
1499/**
1500 * @interface_method_impl{PDMUSBREG,pfnWakeup}
1501 */
1502static DECLCALLBACK(int) usbMsdWakeup(PPDMUSBINS pUsbIns)
1503{
1504 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1505 LogFlow(("usbMsdUrbReap/#%u:\n", pUsbIns->iInstance));
1506
1507 return RTSemEventSignal(pThis->hEvtDoneQueue);
1508}
1509
1510
1511/**
1512 * @interface_method_impl{PDMUSBREG,pfnUrbCancel}
1513 */
1514static DECLCALLBACK(int) usbMsdUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1515{
1516 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1517 LogFlow(("usbMsdUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1518 RTCritSectEnter(&pThis->CritSect);
1519
1520 /*
1521 * Remove the URB from the to-host queue and move it onto the done queue.
1522 */
1523 if (usbMsdQueueRemove(&pThis->ToHostQueue, pUrb))
1524 usbMsdLinkDone(pThis, pUrb);
1525
1526 RTCritSectLeave(&pThis->CritSect);
1527 return VINF_SUCCESS;
1528}
1529
1530
1531/**
1532 * Wrapper around PDMISCSICONNECTOR::pfnSCSIRequestSend that deals with
1533 * SCSI_REQUEST_SENSE.
1534 *
1535 * @returns VBox status code.
1536 * @param pThis The MSD instance data.
1537 * @param pReq The MSD request.
1538 * @param pszCaller Where we're called from.
1539 */
1540static int usbMsdSubmitScsiCommand(PUSBMSD pThis, PUSBMSDREQ pReq, const char *pszCaller)
1541{
1542 RT_NOREF(pszCaller);
1543 Log(("%s: Entering EXECUTING (dCBWTag=%#x).\n", pszCaller, pReq->Cbw.dCBWTag));
1544 Assert(pReq == pThis->pReq);
1545 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1546
1547 PDMMEDIAEXIOREQSCSITXDIR enmTxDir = pReq->Cbw.dCBWDataTransferLength == 0
1548 ? PDMMEDIAEXIOREQSCSITXDIR_NONE
1549 : (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
1550 ? PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE
1551 : PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
1552
1553 return pThis->Lun0.pIMediaEx->pfnIoReqSendScsiCmd(pThis->Lun0.pIMediaEx, pReq->hIoReq, pReq->Cbw.bCBWLun,
1554 &pReq->Cbw.CBWCB[0], pReq->Cbw.bCBWCBLength, enmTxDir,
1555 pReq->Cbw.dCBWDataTransferLength, NULL, 0,
1556 &pReq->iScsiReqStatus, 20 * RT_MS_1SEC);
1557}
1558
1559
1560/**
1561 * Handle requests sent to the outbound (to device) bulk pipe.
1562 */
1563static int usbMsdHandleBulkHostToDev(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1564{
1565 /*
1566 * Stall the request if the pipe is halted.
1567 */
1568 if (RT_UNLIKELY(pEp->fHalted))
1569 return usbMsdCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1570
1571 /*
1572 * Deal with the URB according to the current state.
1573 */
1574 PUSBMSDREQ pReq = pThis->pReq;
1575 USBMSDREQSTATE enmState = pReq ? pReq->enmState : USBMSDREQSTATE_READY;
1576 switch (enmState)
1577 {
1578 case USBMSDREQSTATE_STATUS:
1579 LogFlow(("usbMsdHandleBulkHostToDev: Skipping pending status.\n"));
1580 pReq->enmState = USBMSDREQSTATE_READY;
1581 /* fall thru */
1582
1583 /*
1584 * We're ready to receive a command. Start off by validating the
1585 * incoming request.
1586 */
1587 case USBMSDREQSTATE_READY:
1588 {
1589 PCUSBCBW pCbw = (PUSBCBW)&pUrb->abData[0];
1590 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[1]))
1591 {
1592 Log(("usbMsd: Bad CBW: cbData=%#x < min=%#x\n", pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[1]) ));
1593 return usbMsdCompleteStall(pThis, NULL, pUrb, "BAD CBW");
1594 }
1595 if (pCbw->dCBWSignature != USBCBW_SIGNATURE)
1596 {
1597 Log(("usbMsd: CBW: Invalid dCBWSignature value: %#x\n", pCbw->dCBWSignature));
1598 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1599 }
1600 Log(("usbMsd: CBW: dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x cbData=%#x fShortNotOk=%RTbool\n",
1601 pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
1602 if (pCbw->bmCBWFlags & ~USBCBW_DIR_MASK)
1603 {
1604 Log(("usbMsd: CBW: Bad bmCBWFlags value: %#x\n", pCbw->bmCBWFlags));
1605 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1606
1607 }
1608 if (pCbw->bCBWLun != 0)
1609 {
1610 Log(("usbMsd: CBW: Bad bCBWLun value: %#x\n", pCbw->bCBWLun));
1611 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1612 }
1613 if (pCbw->bCBWCBLength == 0)
1614 {
1615 Log(("usbMsd: CBW: Bad bCBWCBLength value: %#x\n", pCbw->bCBWCBLength));
1616 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1617 }
1618 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]))
1619 {
1620 Log(("usbMsd: CBW: Mismatching cbData and bCBWCBLength values: %#x vs. %#x (%#x)\n",
1621 pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]), pCbw->bCBWCBLength));
1622 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1623 }
1624 if (pCbw->dCBWDataTransferLength > _1M)
1625 {
1626 Log(("usbMsd: CBW: dCBWDataTransferLength is too large: %#x (%u)\n",
1627 pCbw->dCBWDataTransferLength, pCbw->dCBWDataTransferLength));
1628 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too big transfer");
1629 }
1630
1631 /*
1632 * Make sure we've got a request and a sufficient buffer space.
1633 *
1634 * Note! This will make sure the buffer is ZERO as well, thus
1635 * saving us the trouble of clearing the output buffer on
1636 * failure later.
1637 */
1638 if (!pReq)
1639 {
1640 pReq = usbMsdReqAlloc(pThis);
1641 if (!pReq)
1642 return usbMsdCompleteStall(pThis, NULL, pUrb, "Request allocation failure");
1643 pThis->pReq = pReq;
1644 }
1645 if (!usbMsdReqEnsureBuffer(pThis, pReq, pCbw->dCBWDataTransferLength))
1646 return usbMsdCompleteStall(pThis, NULL, pUrb, "Buffer allocation failure");
1647
1648 /*
1649 * Prepare the request. Kick it off right away if possible.
1650 */
1651 usbMsdReqPrepare(pReq, pCbw);
1652
1653 if ( pReq->Cbw.dCBWDataTransferLength == 0
1654 || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
1655 {
1656 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1657 if (RT_SUCCESS(rc) && rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1658 usbMsdReqComplete(pThis, pReq, rc);
1659 else if (RT_FAILURE(rc))
1660 {
1661 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1662 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
1663 }
1664 }
1665 else
1666 {
1667 Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
1668 pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
1669 }
1670
1671 return usbMsdCompleteOk(pThis, pUrb, pUrb->cbData);
1672 }
1673
1674 /*
1675 * Stuff the data into the buffer.
1676 */
1677 case USBMSDREQSTATE_DATA_FROM_HOST:
1678 {
1679 uint32_t cbData = pUrb->cbData;
1680 uint32_t cbLeft = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1681 if (cbData > cbLeft)
1682 {
1683 Log(("usbMsd: Too much data: cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1684 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbLeft));
1685 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too much data");
1686 }
1687 memcpy(&pReq->pbBuf[pReq->offBuf], &pUrb->abData[0], cbData);
1688 pReq->offBuf += cbData;
1689
1690 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1691 {
1692 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1693 if (RT_SUCCESS(rc) && rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1694 usbMsdReqComplete(pThis, pReq, rc);
1695 else if (RT_FAILURE(rc))
1696 {
1697 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1698 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #2");
1699 }
1700 }
1701 return usbMsdCompleteOk(pThis, pUrb, cbData);
1702 }
1703
1704 /*
1705 * Bad state, stall.
1706 */
1707 case USBMSDREQSTATE_DATA_TO_HOST:
1708 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: DATA_TO_HOST");
1709
1710 case USBMSDREQSTATE_EXECUTING:
1711 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: EXECUTING");
1712
1713 default:
1714 AssertMsgFailed(("enmState=%d\n", enmState));
1715 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state (H2D)");
1716 }
1717}
1718
1719
1720/**
1721 * Handle requests sent to the inbound (to host) bulk pipe.
1722 */
1723static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1724{
1725 /*
1726 * Stall the request if the pipe is halted OR if there is no
1727 * pending request yet.
1728 */
1729 PUSBMSDREQ pReq = pThis->pReq;
1730 if (RT_UNLIKELY(pEp->fHalted || !pReq))
1731 return usbMsdCompleteStall(pThis, NULL, pUrb, pEp->fHalted ? "Halted pipe" : "No request");
1732
1733 /*
1734 * Deal with the URB according to the state.
1735 */
1736 switch (pReq->enmState)
1737 {
1738 /*
1739 * We've data left to transfer to the host.
1740 */
1741 case USBMSDREQSTATE_DATA_TO_HOST:
1742 {
1743 uint32_t cbData = pUrb->cbData;
1744 uint32_t cbCopy = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1745 if (cbData <= cbCopy)
1746 cbCopy = cbData;
1747 else if (pUrb->fShortNotOk)
1748 {
1749 Log(("usbMsd: Requested more data that we've got; cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1750 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbCopy));
1751 return usbMsdCompleteStall(pThis, NULL, pUrb, "Data underrun");
1752 }
1753 memcpy(&pUrb->abData[0], &pReq->pbBuf[pReq->offBuf], cbCopy);
1754 pReq->offBuf += cbCopy;
1755
1756 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1757 {
1758 Log(("usbMsdHandleBulkDevToHost: Entering STATUS\n"));
1759 pReq->enmState = USBMSDREQSTATE_STATUS;
1760 }
1761 return usbMsdCompleteOk(pThis, pUrb, cbCopy);
1762 }
1763
1764 /*
1765 * Status transfer.
1766 */
1767 case USBMSDREQSTATE_STATUS:
1768 {
1769 if ((pUrb->cbData < sizeof(USBCSW)) || (pUrb->cbData > sizeof(USBCSW) && pUrb->fShortNotOk))
1770 {
1771 Log(("usbMsd: Unexpected status request size: %#x (expected %#x), fShortNotOK=%RTbool\n", pUrb->cbData, sizeof(USBCSW), pUrb->fShortNotOk));
1772 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1773 }
1774
1775 /* Enter a CSW into the URB data buffer. */
1776 PUSBCSW pCsw = (PUSBCSW)&pUrb->abData[0];
1777 pCsw->dCSWSignature = USBCSW_SIGNATURE;
1778 pCsw->dCSWTag = pReq->Cbw.dCBWTag;
1779 pCsw->bCSWStatus = pReq->iScsiReqStatus == SCSI_STATUS_OK
1780 ? USBCSW_STATUS_OK
1781 : pReq->iScsiReqStatus < 0xff
1782 ? USBCSW_STATUS_FAILED
1783 : USBCSW_STATUS_PHASE_ERROR;
1784 /** @todo the following is not always accurate; VSCSI needs
1785 * to implement residual counts properly! */
1786 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
1787 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1788 ? 0
1789 : pReq->Cbw.dCBWDataTransferLength;
1790 else
1791 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1792 ? 0
1793 : pReq->Cbw.dCBWDataTransferLength;
1794 Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
1795 pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
1796
1797 Log(("usbMsdHandleBulkDevToHost: Entering READY\n"));
1798 pReq->enmState = USBMSDREQSTATE_READY;
1799 return usbMsdCompleteOk(pThis, pUrb, sizeof(*pCsw));
1800 }
1801
1802 /*
1803 * Status request before we've received all (or even any) data.
1804 * Linux 2.4.31 does this sometimes. The recommended behavior is to
1805 * to accept the current data amount and execute the request. (The
1806 * alternative behavior is to stall.)
1807 */
1808 case USBMSDREQSTATE_DATA_FROM_HOST:
1809 {
1810 if (pUrb->cbData != sizeof(USBCSW))
1811 {
1812 Log(("usbMsdHandleBulkDevToHost: DATA_FROM_HOST; cbData=%#x -> stall\n", pUrb->cbData));
1813 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1814 }
1815
1816 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkDevToHost");
1817 if (RT_SUCCESS(rc) && rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1818 usbMsdReqComplete(pThis, pReq, rc);
1819 else if (RT_FAILURE(rc))
1820 {
1821 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1822 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #3");
1823 }
1824 }
1825 /* fall thru */
1826
1827 /*
1828 * The SCSI command is still pending, queue the URB awaiting its
1829 * completion.
1830 */
1831 case USBMSDREQSTATE_EXECUTING:
1832 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1833 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1834 return VINF_SUCCESS;
1835
1836 /*
1837 * Bad states, stall.
1838 */
1839 case USBMSDREQSTATE_READY:
1840 Log(("usbMsdHandleBulkDevToHost: enmState=READ(%d) (cbData=%#x)\n", pReq->enmState, pUrb->cbData));
1841 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state D2H: READY");
1842
1843 default:
1844 Log(("usbMsdHandleBulkDevToHost: enmState=%d cbData=%#x\n", pReq->enmState, pUrb->cbData));
1845 return usbMsdCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1846 }
1847}
1848
1849
1850/**
1851 * Handles request send to the default control pipe.
1852 */
1853static int usbMsdHandleDefaultPipe(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1854{
1855 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1856 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1857
1858 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1859 {
1860 switch (pSetup->bRequest)
1861 {
1862 case VUSB_REQ_GET_DESCRIPTOR:
1863 {
1864 if (pSetup->bmRequestType != (VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST))
1865 {
1866 Log(("usbMsd: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
1867 return usbMsdCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1868 }
1869
1870 switch (pSetup->wValue >> 8)
1871 {
1872 uint32_t cbCopy;
1873
1874 case VUSB_DT_STRING:
1875 Log(("usbMsd: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1876 break;
1877 case VUSB_DT_DEVICE_QUALIFIER:
1878 Log(("usbMsd: GET_DESCRIPTOR DT_DEVICE_QUALIFIER wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1879 /* Returned data is written after the setup message. */
1880 cbCopy = pUrb->cbData - sizeof(*pSetup);
1881 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdDeviceQualifier));
1882 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdDeviceQualifier, cbCopy);
1883 return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1884 case VUSB_DT_BOS:
1885 Log(("usbMsd: GET_DESCRIPTOR DT_BOS wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1886 /* Returned data is written after the setup message. */
1887 cbCopy = pUrb->cbData - sizeof(*pSetup);
1888 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdBOS));
1889 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdBOS, cbCopy);
1890 return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1891 default:
1892 Log(("usbMsd: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1893 break;
1894 }
1895 break;
1896 }
1897
1898 case VUSB_REQ_CLEAR_FEATURE:
1899 break;
1900 }
1901
1902 /** @todo implement this. */
1903 Log(("usbMsd: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1904 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1905
1906 usbMsdCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1907 }
1908 /* 3.1 Bulk-Only Mass Storage Reset */
1909 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
1910 && pSetup->bRequest == 0xff
1911 && !pSetup->wValue
1912 && !pSetup->wLength
1913 && pSetup->wIndex == 0)
1914 {
1915 Log(("usbMsdHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
1916 return usbMsdResetWorker(pThis, pUrb, false /*fSetConfig*/);
1917 }
1918 /* 3.2 Get Max LUN, may stall if we like (but we don't). */
1919 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE | VUSB_DIR_TO_HOST)
1920 && pSetup->bRequest == 0xfe
1921 && !pSetup->wValue
1922 && pSetup->wLength == 1
1923 && pSetup->wIndex == 0)
1924 {
1925 *(uint8_t *)(pSetup + 1) = 0; /* max lun is 0 */
1926 usbMsdCompleteOk(pThis, pUrb, 1);
1927 }
1928 else
1929 {
1930 Log(("usbMsd: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1931 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1932 return usbMsdCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1933 }
1934
1935 return VINF_SUCCESS;
1936}
1937
1938
1939/**
1940 * @interface_method_impl{PDMUSBREG,pfnUrbQueue}
1941 */
1942static DECLCALLBACK(int) usbMsdQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1943{
1944 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1945 LogFlow(("usbMsdQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
1946 RTCritSectEnter(&pThis->CritSect);
1947
1948 /*
1949 * Parse on a per end-point basis.
1950 */
1951 int rc;
1952 switch (pUrb->EndPt)
1953 {
1954 case 0:
1955 rc = usbMsdHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1956 break;
1957
1958 case 0x81:
1959 AssertFailed();
1960 case 0x01:
1961 rc = usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
1962 break;
1963
1964 case 0x02:
1965 rc = usbMsdHandleBulkHostToDev(pThis, &pThis->aEps[2], pUrb);
1966 break;
1967
1968 default:
1969 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1970 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1971 break;
1972 }
1973
1974 RTCritSectLeave(&pThis->CritSect);
1975 return rc;
1976}
1977
1978
1979/**
1980 * @interface_method_impl{PDMUSBREG,pfnUsbClearHaltedEndpoint}
1981 */
1982static DECLCALLBACK(int) usbMsdUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1983{
1984 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1985 LogFlow(("usbMsdUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
1986
1987 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1988 {
1989 RTCritSectEnter(&pThis->CritSect);
1990 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1991 RTCritSectLeave(&pThis->CritSect);
1992 }
1993
1994 return VINF_SUCCESS;
1995}
1996
1997
1998/**
1999 * @interface_method_impl{PDMUSBREG,pfnUsbSetInterface}
2000 */
2001static DECLCALLBACK(int) usbMsdUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
2002{
2003 RT_NOREF(pUsbIns, bInterfaceNumber, bAlternateSetting);
2004 LogFlow(("usbMsdUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
2005 Assert(bAlternateSetting == 0);
2006 return VINF_SUCCESS;
2007}
2008
2009
2010/**
2011 * @interface_method_impl{PDMUSBREG,pfnUsbSetConfiguration}
2012 */
2013static DECLCALLBACK(int) usbMsdUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
2014 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
2015{
2016 RT_NOREF(pvOldCfgDesc, pvOldIfState, pvNewCfgDesc);
2017 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2018 LogFlow(("usbMsdUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
2019 Assert(bConfigurationValue == 1);
2020 RTCritSectEnter(&pThis->CritSect);
2021
2022 /*
2023 * If the same config is applied more than once, it's a kind of reset.
2024 */
2025 if (pThis->bConfigurationValue == bConfigurationValue)
2026 usbMsdResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
2027 pThis->bConfigurationValue = bConfigurationValue;
2028
2029 RTCritSectLeave(&pThis->CritSect);
2030 return VINF_SUCCESS;
2031}
2032
2033
2034/**
2035 * @interface_method_impl{PDMUSBREG,pfnUsbGetDescriptorCache}
2036 */
2037static DECLCALLBACK(PCPDMUSBDESCCACHE) usbMsdUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
2038{
2039 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2040 LogFlow(("usbMsdUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
2041 if (pThis->pUsbIns->enmSpeed == VUSB_SPEED_SUPER)
2042 return pThis->fIsCdrom ? &g_UsbCdDescCacheSS : &g_UsbMsdDescCacheSS;
2043 else if (pThis->pUsbIns->enmSpeed == VUSB_SPEED_HIGH)
2044 return pThis->fIsCdrom ? &g_UsbCdDescCacheHS : &g_UsbMsdDescCacheHS;
2045 else
2046 return pThis->fIsCdrom ? &g_UsbCdDescCacheFS : &g_UsbMsdDescCacheFS;
2047}
2048
2049
2050/**
2051 * @interface_method_impl{PDMUSBREG,pfnUsbReset}
2052 */
2053static DECLCALLBACK(int) usbMsdUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
2054{
2055 RT_NOREF(fResetOnLinux);
2056 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2057 LogFlow(("usbMsdUsbReset/#%u:\n", pUsbIns->iInstance));
2058 RTCritSectEnter(&pThis->CritSect);
2059
2060 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2061
2062 RTCritSectLeave(&pThis->CritSect);
2063 return rc;
2064}
2065
2066
2067/**
2068 * @interface_method_impl{PDMUSBREG,pfnVMSuspend}
2069 */
2070static DECLCALLBACK(void) usbMsdVMSuspend(PPDMUSBINS pUsbIns)
2071{
2072 LogFlow(("usbMsdVMSuspend/#%u:\n", pUsbIns->iInstance));
2073 usbMsdSuspendOrPowerOff(pUsbIns);
2074}
2075
2076
2077/**
2078 * @interface_method_impl{PDMUSBREG,pfnVMSuspend}
2079 */
2080static DECLCALLBACK(void) usbMsdVMPowerOff(PPDMUSBINS pUsbIns)
2081{
2082 LogFlow(("usbMsdVMPowerOff/#%u:\n", pUsbIns->iInstance));
2083 usbMsdSuspendOrPowerOff(pUsbIns);
2084}
2085
2086
2087/**
2088 * @interface_method_impl{PDMUSBREG,pfnDriverAttach}
2089 */
2090static DECLCALLBACK(int) usbMsdDriverAttach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
2091{
2092 RT_NOREF(fFlags);
2093 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2094
2095 LogFlow(("usbMsdDriverAttach/#%u:\n", pUsbIns->iInstance));
2096
2097 AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
2098 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2099 ("UsbMsd: Device does not support hotplugging\n"));
2100
2101 /* the usual paranoia */
2102 AssertRelease(!pThis->Lun0.pIBase);
2103 AssertRelease(!pThis->Lun0.pIMedia);
2104 AssertRelease(!pThis->Lun0.pIMediaEx);
2105
2106 /*
2107 * Try attach the block device and get the interfaces,
2108 * required as well as optional.
2109 */
2110 int rc = PDMUsbHlpDriverAttach(pUsbIns, iLUN, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, NULL);
2111 if (RT_SUCCESS(rc))
2112 {
2113 /* Get media and extended media interface. */
2114 pThis->Lun0.pIMedia = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIA);
2115 AssertMsgReturn(pThis->Lun0.pIMedia, ("Missing media interface below\n"), VERR_PDM_MISSING_INTERFACE);
2116 pThis->Lun0.pIMediaEx = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIAEX);
2117 AssertMsgReturn(pThis->Lun0.pIMediaEx, ("Missing extended media interface below\n"), VERR_PDM_MISSING_INTERFACE);
2118
2119 rc = pThis->Lun0.pIMediaEx->pfnIoReqAllocSizeSet(pThis->Lun0.pIMediaEx, sizeof(USBMSDREQ));
2120 AssertMsgRCReturn(rc, ("MSD failed to set I/O request size!\n"), VERR_PDM_MISSING_INTERFACE);
2121 }
2122 else
2123 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", iLUN, rc));
2124
2125 if (RT_FAILURE(rc))
2126 {
2127 pThis->Lun0.pIBase = NULL;
2128 pThis->Lun0.pIMedia = NULL;
2129 pThis->Lun0.pIMediaEx = NULL;
2130 }
2131
2132 pThis->fIsCdrom = false;
2133 PDMMEDIATYPE enmType = pThis->Lun0.pIMedia->pfnGetType(pThis->Lun0.pIMedia);
2134 /* Anything else will be reported as a hard disk. */
2135 if (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
2136 pThis->fIsCdrom = true;
2137
2138 return rc;
2139}
2140
2141
2142/**
2143 * @interface_method_impl{PDMUSBREG,pfnDriverDetach}
2144 */
2145static DECLCALLBACK(void) usbMsdDriverDetach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
2146{
2147 RT_NOREF(iLUN, fFlags);
2148 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2149
2150 LogFlow(("usbMsdDriverDetach/#%u:\n", pUsbIns->iInstance));
2151
2152 AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
2153 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2154 ("UsbMsd: Device does not support hotplugging\n"));
2155
2156 if (pThis->pReq)
2157 {
2158 usbMsdReqFree(pThis, pThis->pReq);
2159 pThis->pReq = NULL;
2160 }
2161
2162 /*
2163 * Zero some important members.
2164 */
2165 pThis->Lun0.pIBase = NULL;
2166 pThis->Lun0.pIMedia = NULL;
2167 pThis->Lun0.pIMediaEx = NULL;
2168}
2169
2170
2171/**
2172 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
2173 * Callback employed by usbMsdVMReset.}
2174 */
2175static DECLCALLBACK(bool) usbMsdIsAsyncResetDone(PPDMUSBINS pUsbIns)
2176{
2177 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2178
2179 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
2180 return false;
2181 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2182
2183 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2184 AssertRC(rc);
2185 return true;
2186}
2187
2188/**
2189 * @interface_method_impl{PDMDEVREG,pfnReset}
2190 */
2191static DECLCALLBACK(void) usbMsdVMReset(PPDMUSBINS pUsbIns)
2192{
2193 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2194
2195 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
2196 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
2197 PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncResetDone);
2198 else
2199 {
2200 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2201 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2202 AssertRC(rc);
2203 }
2204}
2205
2206
2207/**
2208 * @interface_method_impl{PDMUSBREG,pfnDestruct}
2209 */
2210static DECLCALLBACK(void) usbMsdDestruct(PPDMUSBINS pUsbIns)
2211{
2212 PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns);
2213 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2214 LogFlow(("usbMsdDestruct/#%u:\n", pUsbIns->iInstance));
2215
2216 if (RTCritSectIsInitialized(&pThis->CritSect))
2217 {
2218 RTCritSectEnter(&pThis->CritSect);
2219 RTCritSectLeave(&pThis->CritSect);
2220 RTCritSectDelete(&pThis->CritSect);
2221 }
2222
2223 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2224 {
2225 RTSemEventDestroy(pThis->hEvtDoneQueue);
2226 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2227 }
2228
2229 if (pThis->hEvtReset != NIL_RTSEMEVENTMULTI)
2230 {
2231 RTSemEventMultiDestroy(pThis->hEvtReset);
2232 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
2233 }
2234}
2235
2236
2237/**
2238 * @interface_method_impl{PDMUSBREG,pfnConstruct}
2239 */
2240static DECLCALLBACK(int) usbMsdConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2241{
2242 RT_NOREF(pCfgGlobal);
2243 PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns);
2244 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2245 Log(("usbMsdConstruct/#%u:\n", iInstance));
2246
2247 /*
2248 * Perform the basic structure initialization first so the destructor
2249 * will not misbehave.
2250 */
2251 pThis->pUsbIns = pUsbIns;
2252 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2253 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
2254 pThis->Lun0.IBase.pfnQueryInterface = usbMsdLun0QueryInterface;
2255 pThis->Lun0.IMediaPort.pfnQueryDeviceLocation = usbMsdLun0QueryDeviceLocation;
2256 pThis->Lun0.IMediaExPort.pfnIoReqCompleteNotify = usbMsdLun0IoReqCompleteNotify;
2257 pThis->Lun0.IMediaExPort.pfnIoReqCopyFromBuf = usbMsdLun0IoReqCopyFromBuf;
2258 pThis->Lun0.IMediaExPort.pfnIoReqCopyToBuf = usbMsdLun0IoReqCopyToBuf;
2259 pThis->Lun0.IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
2260 pThis->Lun0.IMediaExPort.pfnIoReqStateChanged = usbMsdLun0IoReqStateChanged;
2261 pThis->Lun0.IMediaExPort.pfnMediumEjected = usbMsdLun0MediumEjected;
2262 usbMsdQueueInit(&pThis->ToHostQueue);
2263 usbMsdQueueInit(&pThis->DoneQueue);
2264
2265 int rc = RTCritSectInit(&pThis->CritSect);
2266 AssertRCReturn(rc, rc);
2267
2268 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2269 AssertRCReturn(rc, rc);
2270
2271 rc = RTSemEventMultiCreate(&pThis->hEvtReset);
2272 AssertRCReturn(rc, rc);
2273
2274 /*
2275 * Validate and read the configuration.
2276 */
2277 rc = CFGMR3ValidateConfig(pCfg, "/", "", "", "UsbMsd", iInstance);
2278 if (RT_FAILURE(rc))
2279 return rc;
2280
2281 /*
2282 * Attach the SCSI driver.
2283 */
2284 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, "SCSI Port");
2285 if (RT_FAILURE(rc))
2286 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to attach SCSI driver"));
2287 pThis->Lun0.pIMedia = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIA);
2288 if (!pThis->Lun0.pIMedia)
2289 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
2290 N_("MSD failed to query the PDMIMEDIA from the driver below it"));
2291 pThis->Lun0.pIMediaEx = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIAEX);
2292 if (!pThis->Lun0.pIMediaEx)
2293 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
2294 N_("MSD failed to query the PDMIMEDIAEX from the driver below it"));
2295
2296 /*
2297 * Find out what kind of device we are.
2298 */
2299 pThis->fIsCdrom = false;
2300 PDMMEDIATYPE enmType = pThis->Lun0.pIMedia->pfnGetType(pThis->Lun0.pIMedia);
2301 /* Anything else will be reported as a hard disk. */
2302 if (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
2303 pThis->fIsCdrom = true;
2304
2305 rc = pThis->Lun0.pIMediaEx->pfnIoReqAllocSizeSet(pThis->Lun0.pIMediaEx, sizeof(USBMSDREQ));
2306 if (RT_FAILURE(rc))
2307 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to set I/O request size!"));
2308
2309 /*
2310 * Register the saved state data unit.
2311 */
2312 rc = PDMUsbHlpSSMRegister(pUsbIns, USB_MSD_SAVED_STATE_VERSION, sizeof(*pThis),
2313 NULL, usbMsdLiveExec, NULL,
2314 usbMsdSavePrep, usbMsdSaveExec, NULL,
2315 usbMsdLoadPrep, usbMsdLoadExec, NULL);
2316 if (RT_FAILURE(rc))
2317 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2318 N_("MSD failed to register SSM save state handlers"));
2319
2320 return VINF_SUCCESS;
2321}
2322
2323
2324/**
2325 * The USB Mass Storage Device (MSD) registration record.
2326 */
2327const PDMUSBREG g_UsbMsd =
2328{
2329 /* u32Version */
2330 PDM_USBREG_VERSION,
2331 /* szName */
2332 "Msd",
2333 /* pszDescription */
2334 "USB Mass Storage Device, one LUN.",
2335 /* fFlags */
2336 PDM_USBREG_HIGHSPEED_CAPABLE | PDM_USBREG_SUPERSPEED_CAPABLE
2337 | PDM_USBREG_SAVED_STATE_SUPPORTED,
2338 /* cMaxInstances */
2339 ~0U,
2340 /* cbInstance */
2341 sizeof(USBMSD),
2342 /* pfnConstruct */
2343 usbMsdConstruct,
2344 /* pfnDestruct */
2345 usbMsdDestruct,
2346 /* pfnVMInitComplete */
2347 NULL,
2348 /* pfnVMPowerOn */
2349 NULL,
2350 /* pfnVMReset */
2351 usbMsdVMReset,
2352 /* pfnVMSuspend */
2353 usbMsdVMSuspend,
2354 /* pfnVMResume */
2355 NULL,
2356 /* pfnVMPowerOff */
2357 usbMsdVMPowerOff,
2358 /* pfnHotPlugged */
2359 NULL,
2360 /* pfnHotUnplugged */
2361 NULL,
2362 /* pfnDriverAttach */
2363 usbMsdDriverAttach,
2364 /* pfnDriverDetach */
2365 usbMsdDriverDetach,
2366 /* pfnQueryInterface */
2367 NULL,
2368 /* pfnUsbReset */
2369 usbMsdUsbReset,
2370 /* pfnUsbGetCachedDescriptors */
2371 usbMsdUsbGetDescriptorCache,
2372 /* pfnUsbSetConfiguration */
2373 usbMsdUsbSetConfiguration,
2374 /* pfnUsbSetInterface */
2375 usbMsdUsbSetInterface,
2376 /* pfnUsbClearHaltedEndpoint */
2377 usbMsdUsbClearHaltedEndpoint,
2378 /* pfnUrbNew */
2379 NULL/*usbMsdUrbNew*/,
2380 /* pfnQueue */
2381 usbMsdQueue,
2382 /* pfnUrbCancel */
2383 usbMsdUrbCancel,
2384 /* pfnUrbReap */
2385 usbMsdUrbReap,
2386 /* pfnWakeup */
2387 usbMsdWakeup,
2388 /* u32TheEnd */
2389 PDM_USBREG_VERSION
2390};
2391
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette