VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostBase.cpp@ 67494

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

pdmstorageifs.h: Return the region number on success too

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.1 KB
Line 
1/* $Id: DrvHostBase.cpp 66193 2017-03-22 13:29:33Z vboxsync $ */
2/** @file
3 * DrvHostBase - Host base drive access driver.
4 */
5
6/*
7 * Copyright (C) 2006-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_DRV_HOST_BASE
23
24#include <VBox/vmm/pdmdrv.h>
25#include <VBox/vmm/pdmstorageifs.h>
26#include <iprt/assert.h>
27#include <iprt/file.h>
28#include <iprt/path.h>
29#include <iprt/string.h>
30#include <iprt/thread.h>
31#include <iprt/semaphore.h>
32#include <iprt/uuid.h>
33#include <iprt/asm.h>
34#include <iprt/critsect.h>
35#include <iprt/ctype.h>
36#include <iprt/mem.h>
37
38#include "DrvHostBase.h"
39
40
41
42
43/* -=-=-=-=- IBlock -=-=-=-=- */
44
45/** @interface_method_impl{PDMIMEDIA,pfnRead} */
46static DECLCALLBACK(int) drvHostBaseRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
47{
48 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
49 LogFlow(("%s-%d: drvHostBaseRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n",
50 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbRead, pThis->pszDevice));
51 RTCritSectEnter(&pThis->CritSect);
52
53 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
54 STAM_REL_COUNTER_INC(&pThis->StatReqsRead);
55
56 /*
57 * Check the state.
58 */
59 int rc;
60 if (pThis->fMediaPresent)
61 {
62 /*
63 * Seek and read.
64 */
65 rc = drvHostBaseReadOs(pThis, off, pvBuf, cbRead);
66 if (RT_SUCCESS(rc))
67 {
68 Log2(("%s-%d: drvHostBaseReadOs: off=%#llx cbRead=%#x\n"
69 "%16.*Rhxd\n",
70 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbRead, cbRead, pvBuf));
71 }
72 else
73 Log(("%s-%d: drvHostBaseRead: drvHostBaseReadOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
74 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
75 off, pvBuf, cbRead, rc, pThis->pszDevice));
76 }
77 else
78 rc = VERR_MEDIA_NOT_PRESENT;
79
80 if (RT_SUCCESS(rc))
81 {
82 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
83 STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbRead);
84 }
85 else
86 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
87
88 RTCritSectLeave(&pThis->CritSect);
89 LogFlow(("%s-%d: drvHostBaseRead: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
90 return rc;
91}
92
93
94/** @interface_method_impl{PDMIMEDIA,pfnWrite} */
95static DECLCALLBACK(int) drvHostBaseWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
96{
97 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
98 LogFlow(("%s-%d: drvHostBaseWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n",
99 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbWrite, pThis->pszDevice));
100 Log2(("%s-%d: drvHostBaseWrite: off=%#llx cbWrite=%#x\n"
101 "%16.*Rhxd\n",
102 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbWrite, cbWrite, pvBuf));
103 RTCritSectEnter(&pThis->CritSect);
104
105 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
106 STAM_REL_COUNTER_INC(&pThis->StatReqsWrite);
107
108 /*
109 * Check the state.
110 */
111 int rc;
112 if (!pThis->fReadOnly)
113 {
114 if (pThis->fMediaPresent)
115 {
116 /*
117 * Seek and write.
118 */
119 rc = drvHostBaseWriteOs(pThis, off, pvBuf, cbWrite);
120 if (RT_FAILURE(rc))
121 Log(("%s-%d: drvHostBaseWrite: drvHostBaseWriteOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
122 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
123 off, pvBuf, cbWrite, rc, pThis->pszDevice));
124 }
125 else
126 rc = VERR_MEDIA_NOT_PRESENT;
127 }
128 else
129 rc = VERR_WRITE_PROTECT;
130
131 if (RT_SUCCESS(rc))
132 {
133 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
134 STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbWrite);
135 }
136 else
137 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
138
139 RTCritSectLeave(&pThis->CritSect);
140 LogFlow(("%s-%d: drvHostBaseWrite: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
141 return rc;
142}
143
144
145/** @interface_method_impl{PDMIMEDIA,pfnFlush} */
146static DECLCALLBACK(int) drvHostBaseFlush(PPDMIMEDIA pInterface)
147{
148 int rc;
149 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
150 LogFlow(("%s-%d: drvHostBaseFlush: (%s)\n",
151 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice));
152 RTCritSectEnter(&pThis->CritSect);
153
154 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
155 STAM_REL_COUNTER_INC(&pThis->StatReqsFlush);
156
157 if (pThis->fMediaPresent)
158 rc = drvHostBaseFlushOs(pThis);
159 else
160 rc = VERR_MEDIA_NOT_PRESENT;
161
162 if (RT_SUCCESS(rc))
163 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
164 else
165 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
166
167 RTCritSectLeave(&pThis->CritSect);
168 LogFlow(("%s-%d: drvHostBaseFlush: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
169 return rc;
170}
171
172
173/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
174static DECLCALLBACK(bool) drvHostBaseIsReadOnly(PPDMIMEDIA pInterface)
175{
176 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
177 return pThis->fReadOnly;
178}
179
180
181/** @interface_method_impl{PDMIMEDIA,pfnIsNonRotational} */
182static DECLCALLBACK(bool) drvHostBaseIsNonRotational(PPDMIMEDIA pInterface)
183{
184 RT_NOREF1(pInterface);
185 return false;
186}
187
188
189/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
190static DECLCALLBACK(uint64_t) drvHostBaseGetSize(PPDMIMEDIA pInterface)
191{
192 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
193 RTCritSectEnter(&pThis->CritSect);
194
195 uint64_t cb = 0;
196 if (pThis->fMediaPresent)
197 cb = pThis->cbSize;
198
199 RTCritSectLeave(&pThis->CritSect);
200 LogFlow(("%s-%d: drvHostBaseGetSize: returns %llu\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, cb));
201 return cb;
202}
203
204
205/** @interface_method_impl{PDMIMEDIA,pfnGetType} */
206static DECLCALLBACK(PDMMEDIATYPE) drvHostBaseGetType(PPDMIMEDIA pInterface)
207{
208 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
209 LogFlow(("%s-%d: drvHostBaseGetType: returns %d\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->enmType));
210 return pThis->enmType;
211}
212
213
214/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
215static DECLCALLBACK(int) drvHostBaseGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
216{
217 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
218
219 *pUuid = pThis->Uuid;
220
221 LogFlow(("%s-%d: drvHostBaseGetUuid: returns VINF_SUCCESS *pUuid=%RTuuid\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pUuid));
222 return VINF_SUCCESS;
223}
224
225
226/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
227static DECLCALLBACK(int) drvHostBaseGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
228{
229 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
230 RTCritSectEnter(&pThis->CritSect);
231
232 int rc = VINF_SUCCESS;
233 if (pThis->fMediaPresent)
234 {
235 if ( pThis->PCHSGeometry.cCylinders > 0
236 && pThis->PCHSGeometry.cHeads > 0
237 && pThis->PCHSGeometry.cSectors > 0)
238 {
239 *pPCHSGeometry = pThis->PCHSGeometry;
240 }
241 else
242 rc = VERR_PDM_GEOMETRY_NOT_SET;
243 }
244 else
245 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
246
247 RTCritSectLeave(&pThis->CritSect);
248 LogFlow(("%s-%d: %s: returns %Rrc CHS={%d,%d,%d}\n",
249 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, rc,
250 pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
251 return rc;
252}
253
254
255/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
256static DECLCALLBACK(int) drvHostBaseSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
257{
258 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
259 LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
260 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__,
261 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
262 RTCritSectEnter(&pThis->CritSect);
263
264 int rc = VINF_SUCCESS;
265 if (pThis->fMediaPresent)
266 {
267 pThis->PCHSGeometry = *pPCHSGeometry;
268 }
269 else
270 {
271 AssertMsgFailed(("Invalid state! Not mounted!\n"));
272 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
273 }
274
275 RTCritSectLeave(&pThis->CritSect);
276 return rc;
277}
278
279
280/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
281static DECLCALLBACK(int) drvHostBaseGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
282{
283 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
284 RTCritSectEnter(&pThis->CritSect);
285
286 int rc = VINF_SUCCESS;
287 if (pThis->fMediaPresent)
288 {
289 if ( pThis->LCHSGeometry.cCylinders > 0
290 && pThis->LCHSGeometry.cHeads > 0
291 && pThis->LCHSGeometry.cSectors > 0)
292 {
293 *pLCHSGeometry = pThis->LCHSGeometry;
294 }
295 else
296 rc = VERR_PDM_GEOMETRY_NOT_SET;
297 }
298 else
299 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
300
301 RTCritSectLeave(&pThis->CritSect);
302 LogFlow(("%s-%d: %s: returns %Rrc CHS={%d,%d,%d}\n",
303 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, rc,
304 pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
305 return rc;
306}
307
308
309/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
310static DECLCALLBACK(int) drvHostBaseSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
311{
312 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
313 LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
314 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__,
315 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
316 RTCritSectEnter(&pThis->CritSect);
317
318 int rc = VINF_SUCCESS;
319 if (pThis->fMediaPresent)
320 {
321 pThis->LCHSGeometry = *pLCHSGeometry;
322 }
323 else
324 {
325 AssertMsgFailed(("Invalid state! Not mounted!\n"));
326 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
327 }
328
329 RTCritSectLeave(&pThis->CritSect);
330 return rc;
331}
332
333
334/** @interface_method_impl{PDMIMEDIA,pfnBiosIsVisible} */
335static DECLCALLBACK(bool) drvHostBaseIsVisible(PPDMIMEDIA pInterface)
336{
337 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
338 return pThis->fBiosVisible;
339}
340
341
342/** @interface_method_impl{PDMIMEDIA,pfnGetRegionCount} */
343static DECLCALLBACK(uint32_t) drvHostBaseGetRegionCount(PPDMIMEDIA pInterface)
344{
345 RT_NOREF1(pInterface);
346
347 LogFlowFunc(("\n"));
348 uint32_t cRegions = 1;
349
350 /* For now just return one region for all devices. */
351 /** @todo: Handle CD/DVD passthrough properly. */
352
353 LogFlowFunc(("returns %u\n", cRegions));
354 return cRegions;
355}
356
357/** @interface_method_impl{PDMIMEDIA,pfnQueryRegionProperties} */
358static DECLCALLBACK(int) drvHostBaseQueryRegionProperties(PPDMIMEDIA pInterface, uint32_t uRegion, uint64_t *pu64LbaStart,
359 uint64_t *pcBlocks, uint64_t *pcbBlock,
360 PVDREGIONDATAFORM penmDataForm)
361{
362 LogFlowFunc(("\n"));
363 int rc = VINF_SUCCESS;
364 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
365
366 if (uRegion < 1)
367 {
368 uint64_t cbMedia;
369 rc = drvHostBaseGetMediaSizeOs(pThis, &cbMedia);
370 if (RT_SUCCESS(rc))
371 {
372 uint64_t cbBlock = 0;
373
374 if (pThis->enmType == PDMMEDIATYPE_DVD)
375 cbBlock = 2048;
376 else
377 cbBlock = 512; /* Floppy. */
378
379 if (pu64LbaStart)
380 *pu64LbaStart = 0;
381 if (pcBlocks)
382 *pcBlocks = cbMedia / cbBlock;
383 if (pcbBlock)
384 *pcbBlock = cbBlock;
385 if (penmDataForm)
386 *penmDataForm = VDREGIONDATAFORM_RAW;
387 }
388 }
389 else
390 rc = VERR_NOT_FOUND;
391
392 LogFlowFunc(("returns %Rrc\n", rc));
393 return rc;
394}
395
396/** @interface_method_impl{PDMIMEDIA,pfnQueryRegionPropertiesForLba} */
397static DECLCALLBACK(int) drvHostBaseQueryRegionPropertiesForLba(PPDMIMEDIA pInterface, uint64_t u64LbaStart,
398 uint32_t *puRegion, uint64_t *pcBlocks,
399 uint64_t *pcbBlock, PVDREGIONDATAFORM penmDataForm)
400{
401 LogFlowFunc(("\n"));
402 int rc = VINF_SUCCESS;
403 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
404 uint64_t cbMedia;
405 uint64_t cbBlock = 0;
406
407 if (pThis->enmType == PDMMEDIATYPE_DVD)
408 cbBlock = 2048;
409 else
410 cbBlock = 512; /* Floppy. */
411
412 rc = drvHostBaseGetMediaSizeOs(pThis, &cbMedia);
413 if ( RT_SUCCESS(rc)
414 && u64LbaStart < cbMedia / cbBlock)
415 {
416 rc = VERR_NOT_FOUND;
417
418 if (puRegion)
419 *puRegion = 0;
420 if (pcBlocks)
421 *pcBlocks = cbMedia / cbBlock;
422 if (pcbBlock)
423 *pcbBlock = cbBlock;
424 if (penmDataForm)
425 *penmDataForm = VDREGIONDATAFORM_RAW;
426 }
427 else
428 rc = VERR_NOT_FOUND;
429
430 LogFlowFunc(("returns %Rrc\n", rc));
431 return rc;
432}
433
434
435
436/* -=-=-=-=- IMediaEx -=-=-=-=- */
437
438DECLHIDDEN(int) drvHostBaseBufferRetain(PDRVHOSTBASE pThis, PDRVHOSTBASEREQ pReq, size_t cbBuf, bool fWrite, void **ppvBuf)
439{
440 int rc = VINF_SUCCESS;
441
442 if (pThis->cbBuf < cbBuf)
443 {
444 RTMemFree(pThis->pvBuf);
445 pThis->cbBuf = 0;
446 pThis->pvBuf = RTMemAlloc(cbBuf);
447 if (pThis->pvBuf)
448 pThis->cbBuf = cbBuf;
449 else
450 rc = VERR_NO_MEMORY;
451 }
452
453 if (RT_SUCCESS(rc) && fWrite)
454 {
455 RTSGSEG Seg;
456 RTSGBUF SgBuf;
457
458 Seg.pvSeg = pThis->pvBuf;
459 Seg.cbSeg = cbBuf;
460 RTSgBufInit(&SgBuf, &Seg, 1);
461 rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, (PDMMEDIAEXIOREQ)pReq,
462 &pReq->abAlloc[0], 0, &SgBuf, cbBuf);
463 }
464
465 if (RT_SUCCESS(rc))
466 *ppvBuf = pThis->pvBuf;
467
468 return rc;
469}
470
471DECLHIDDEN(int) drvHostBaseBufferRelease(PDRVHOSTBASE pThis, PDRVHOSTBASEREQ pReq, size_t cbBuf, bool fWrite, void *pvBuf)
472{
473 int rc = VINF_SUCCESS;
474
475 if (!fWrite)
476 {
477 RTSGSEG Seg;
478 RTSGBUF SgBuf;
479
480 Seg.pvSeg = pvBuf;
481 Seg.cbSeg = cbBuf;
482 RTSgBufInit(&SgBuf, &Seg, 1);
483 rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, (PDMMEDIAEXIOREQ)pReq,
484 &pReq->abAlloc[0], 0, &SgBuf, cbBuf);
485 }
486
487 return rc;
488}
489
490/** @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures} */
491static DECLCALLBACK(int) drvHostBaseQueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
492{
493 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
494
495 *pfFeatures = pThis->IMediaEx.pfnIoReqSendScsiCmd ? PDMIMEDIAEX_FEATURE_F_RAWSCSICMD : 0;
496 return VINF_SUCCESS;
497}
498
499/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet} */
500static DECLCALLBACK(int) drvHostBaseIoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
501{
502 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
503
504 pThis->cbIoReqAlloc = RT_OFFSETOF(DRVHOSTBASEREQ, abAlloc[cbIoReqAlloc]);
505 return VINF_SUCCESS;
506}
507
508/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc} */
509static DECLCALLBACK(int) drvHostBaseIoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
510 PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
511{
512 RT_NOREF2(uIoReqId, fFlags);
513
514 int rc = VINF_SUCCESS;
515 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
516 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)RTMemAllocZ(pThis->cbIoReqAlloc);
517 if (RT_LIKELY(pReq))
518 {
519 pReq->cbReq = 0;
520 pReq->cbResidual = 0;
521 *phIoReq = (PDMMEDIAEXIOREQ)pReq;
522 *ppvIoReqAlloc = &pReq->abAlloc[0];
523 }
524 else
525 rc = VERR_NO_MEMORY;
526
527 return rc;
528}
529
530/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree} */
531static DECLCALLBACK(int) drvHostBaseIoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
532{
533 RT_NOREF1(pInterface);
534 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
535
536 RTMemFree(pReq);
537 return VINF_SUCCESS;
538}
539
540/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual} */
541static DECLCALLBACK(int) drvHostBaseIoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
542{
543 RT_NOREF1(pInterface);
544 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
545
546 *pcbResidual = pReq->cbResidual;
547 return VINF_SUCCESS;
548}
549
550/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryXferSize} */
551static DECLCALLBACK(int) drvHostBaseIoReqQueryXferSize(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)
552{
553 RT_NOREF1(pInterface);
554 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
555
556 *pcbXfer = pReq->cbReq;
557 return VINF_SUCCESS;
558}
559
560/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll} */
561static DECLCALLBACK(int) drvHostBaseIoReqCancelAll(PPDMIMEDIAEX pInterface)
562{
563 RT_NOREF1(pInterface);
564 return VINF_SUCCESS;
565}
566
567/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel} */
568static DECLCALLBACK(int) drvHostBaseIoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
569{
570 RT_NOREF2(pInterface, uIoReqId);
571 return VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND;
572}
573
574/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead} */
575static DECLCALLBACK(int) drvHostBaseIoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
576{
577 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
578 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
579 LogFlow(("%s-%d: drvHostBaseIoReqRead: off=%#llx cbRead=%#x (%s)\n",
580 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbRead, pThis->pszDevice));
581 RTCritSectEnter(&pThis->CritSect);
582
583 pReq->cbReq = cbRead;
584 pReq->cbResidual = cbRead;
585
586 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
587 STAM_REL_COUNTER_INC(&pThis->StatReqsRead);
588
589 /*
590 * Check the state.
591 */
592 int rc;
593 if (pThis->fMediaPresent)
594 {
595 void *pvBuf;
596 rc = drvHostBaseBufferRetain(pThis, pReq, cbRead, false, &pvBuf);
597 if (RT_SUCCESS(rc))
598 {
599 /*
600 * Seek and read.
601 */
602 rc = drvHostBaseReadOs(pThis, off, pvBuf, cbRead);
603 if (RT_SUCCESS(rc))
604 {
605 Log2(("%s-%d: drvHostBaseReadOs: off=%#llx cbRead=%#x\n"
606 "%16.*Rhxd\n",
607 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbRead, cbRead, pvBuf));
608
609 pReq->cbResidual = 0;
610 }
611 else
612 Log(("%s-%d: drvHostBaseIoReqRead: drvHostBaseReadOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
613 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
614 off, pvBuf, cbRead, rc, pThis->pszDevice));
615
616 rc = drvHostBaseBufferRelease(pThis, pReq, cbRead, false, pvBuf);
617 }
618 else
619 Log(("%s-%d: drvHostBaseIoReqRead: drvHostBaseBufferRetain(%#llx, %p, %#x) -> %Rrc ('%s')\n",
620 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
621 off, pvBuf, cbRead, rc, pThis->pszDevice));
622 }
623 else
624 rc = VERR_MEDIA_NOT_PRESENT;
625
626 if (RT_SUCCESS(rc))
627 {
628 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
629 STAM_REL_COUNTER_INC(&pThis->StatBytesRead);
630 }
631 else
632 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
633
634 RTCritSectLeave(&pThis->CritSect);
635 LogFlow(("%s-%d: drvHostBaseIoReqRead: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
636 return rc;
637}
638
639/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite} */
640static DECLCALLBACK(int) drvHostBaseIoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
641{
642 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
643 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
644 LogFlow(("%s-%d: drvHostBaseIoReqWrite: off=%#llx cbWrite=%#x (%s)\n",
645 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbWrite, pThis->pszDevice));
646 RTCritSectEnter(&pThis->CritSect);
647
648 pReq->cbReq = cbWrite;
649 pReq->cbResidual = cbWrite;
650
651 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
652 STAM_REL_COUNTER_INC(&pThis->StatReqsWrite);
653
654 /*
655 * Check the state.
656 */
657 int rc;
658 if (!pThis->fReadOnly)
659 {
660 if (pThis->fMediaPresent)
661 {
662 void *pvBuf;
663 rc = drvHostBaseBufferRetain(pThis, pReq, cbWrite, true, &pvBuf);
664 if (RT_SUCCESS(rc))
665 {
666 Log2(("%s-%d: drvHostBaseIoReqWrite: off=%#llx cbWrite=%#x\n"
667 "%16.*Rhxd\n",
668 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbWrite, cbWrite, pvBuf));
669 /*
670 * Seek and write.
671 */
672 rc = drvHostBaseWriteOs(pThis, off, pvBuf, cbWrite);
673 if (RT_FAILURE(rc))
674 Log(("%s-%d: drvHostBaseIoReqWrite: drvHostBaseWriteOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
675 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
676 off, pvBuf, cbWrite, rc, pThis->pszDevice));
677 else
678 pReq->cbResidual = 0;
679
680 rc = drvHostBaseBufferRelease(pThis, pReq, cbWrite, true, pvBuf);
681 }
682 }
683 else
684 rc = VERR_MEDIA_NOT_PRESENT;
685 }
686 else
687 rc = VERR_WRITE_PROTECT;
688
689 if (RT_SUCCESS(rc))
690 {
691 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
692 STAM_REL_COUNTER_INC(&pThis->StatBytesWritten);
693 }
694 else
695 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
696
697 RTCritSectLeave(&pThis->CritSect);
698 LogFlow(("%s-%d: drvHostBaseIoReqWrite: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
699 return rc;
700}
701
702/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush} */
703static DECLCALLBACK(int) drvHostBaseIoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
704{
705 RT_NOREF1(hIoReq);
706
707 int rc;
708 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
709 LogFlow(("%s-%d: drvHostBaseIoReqFlush: (%s)\n",
710 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice));
711 RTCritSectEnter(&pThis->CritSect);
712
713 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
714 STAM_REL_COUNTER_INC(&pThis->StatReqsFlush);
715
716 if (pThis->fMediaPresent)
717 rc = drvHostBaseFlushOs(pThis);
718 else
719 rc = VERR_MEDIA_NOT_PRESENT;
720
721 if (RT_SUCCESS(rc))
722 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
723 else
724 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
725
726 RTCritSectLeave(&pThis->CritSect);
727 LogFlow(("%s-%d: drvHostBaseFlush: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
728 return rc;
729}
730
731/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard} */
732static DECLCALLBACK(int) drvHostBaseIoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
733{
734 RT_NOREF3(pInterface, hIoReq, cRangesMax);
735 return VERR_NOT_SUPPORTED;
736}
737
738/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount} */
739static DECLCALLBACK(uint32_t) drvHostBaseIoReqGetActiveCount(PPDMIMEDIAEX pInterface)
740{
741 RT_NOREF1(pInterface);
742 return 0;
743}
744
745/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount} */
746static DECLCALLBACK(uint32_t) drvHostBaseIoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
747{
748 RT_NOREF1(pInterface);
749 return 0;
750}
751
752/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedStart} */
753static DECLCALLBACK(int) drvHostBaseIoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)
754{
755 RT_NOREF3(pInterface, phIoReq, ppvIoReqAlloc);
756 return VERR_NOT_IMPLEMENTED;
757}
758
759/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext} */
760static DECLCALLBACK(int) drvHostBaseIoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
761 PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
762{
763 RT_NOREF4(pInterface, hIoReq, phIoReqNext, ppvIoReqAllocNext);
764 return VERR_NOT_IMPLEMENTED;
765}
766
767/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave} */
768static DECLCALLBACK(int) drvHostBaseIoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
769{
770 RT_NOREF3(pInterface, pSSM, hIoReq);
771 return VERR_NOT_IMPLEMENTED;
772}
773
774/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad} */
775static DECLCALLBACK(int) drvHostBaseIoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
776{
777 RT_NOREF3(pInterface, pSSM, hIoReq);
778 return VERR_NOT_IMPLEMENTED;
779}
780
781
782
783/* -=-=-=-=- IMount -=-=-=-=- */
784
785/** @interface_method_impl{PDMIMOUNT,pfnUnmount} */
786static DECLCALLBACK(int) drvHostBaseUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)
787{
788 RT_NOREF(fEject);
789 /* While we're not mountable (see drvHostBaseMount), we're unmountable. */
790 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
791 RTCritSectEnter(&pThis->CritSect);
792
793 /*
794 * Validate state.
795 */
796 int rc = VINF_SUCCESS;
797 if (!pThis->fLocked || fForce)
798 {
799 /* Unlock drive if necessary. */
800 if (pThis->fLocked)
801 {
802 if (pThis->pfnDoLock)
803 rc = pThis->pfnDoLock(pThis, false);
804 if (RT_SUCCESS(rc))
805 pThis->fLocked = false;
806 }
807
808 if (fEject)
809 {
810 /*
811 * Eject the disc.
812 */
813 rc = drvHostBaseEjectOs(pThis);
814 }
815
816 /*
817 * Media is no longer present.
818 */
819 DRVHostBaseMediaNotPresent(pThis);
820 }
821 else
822 {
823 Log(("drvHostBaseUnmount: Locked\n"));
824 rc = VERR_PDM_MEDIA_LOCKED;
825 }
826
827 RTCritSectLeave(&pThis->CritSect);
828 LogFlow(("drvHostBaseUnmount: returns %Rrc\n", rc));
829 return rc;
830}
831
832
833/** @interface_method_impl{PDMIMOUNT,pfnIsMounted} */
834static DECLCALLBACK(bool) drvHostBaseIsMounted(PPDMIMOUNT pInterface)
835{
836 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
837 RTCritSectEnter(&pThis->CritSect);
838
839 bool fRc = pThis->fMediaPresent;
840
841 RTCritSectLeave(&pThis->CritSect);
842 return fRc;
843}
844
845
846/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
847static DECLCALLBACK(int) drvHostBaseLock(PPDMIMOUNT pInterface)
848{
849 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
850 RTCritSectEnter(&pThis->CritSect);
851
852 int rc = VINF_SUCCESS;
853 if (!pThis->fLocked)
854 {
855 if (pThis->pfnDoLock)
856 rc = pThis->pfnDoLock(pThis, true);
857 if (RT_SUCCESS(rc))
858 pThis->fLocked = true;
859 }
860 else
861 LogFlow(("%s-%d: drvHostBaseLock: already locked\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
862
863 RTCritSectLeave(&pThis->CritSect);
864 LogFlow(("%s-%d: drvHostBaseLock: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
865 return rc;
866}
867
868
869/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
870static DECLCALLBACK(int) drvHostBaseUnlock(PPDMIMOUNT pInterface)
871{
872 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
873 RTCritSectEnter(&pThis->CritSect);
874
875 int rc = VINF_SUCCESS;
876 if (pThis->fLocked)
877 {
878 if (pThis->pfnDoLock)
879 rc = pThis->pfnDoLock(pThis, false);
880 if (RT_SUCCESS(rc))
881 pThis->fLocked = false;
882 }
883 else
884 LogFlow(("%s-%d: drvHostBaseUnlock: not locked\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
885
886 RTCritSectLeave(&pThis->CritSect);
887 LogFlow(("%s-%d: drvHostBaseUnlock: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
888 return rc;
889}
890
891
892/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
893static DECLCALLBACK(bool) drvHostBaseIsLocked(PPDMIMOUNT pInterface)
894{
895 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
896 RTCritSectEnter(&pThis->CritSect);
897
898 bool fRc = pThis->fLocked;
899
900 RTCritSectLeave(&pThis->CritSect);
901 return fRc;
902}
903
904
905/* -=-=-=-=- IBase -=-=-=-=- */
906
907/**
908 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
909 */
910static DECLCALLBACK(void *) drvHostBaseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
911{
912 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
913 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
914
915 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
916 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
917 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, &pThis->IMount);
918 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, pThis->pDrvMediaExPort ? &pThis->IMediaEx : NULL);
919 return NULL;
920}
921
922
923/* -=-=-=-=- poller thread -=-=-=-=- */
924
925
926/**
927 * Media present.
928 * Query the size and notify the above driver / device.
929 *
930 * @param pThis The instance data.
931 */
932DECLHIDDEN(int) DRVHostBaseMediaPresent(PDRVHOSTBASE pThis)
933{
934 /*
935 * Open the drive.
936 */
937 int rc = drvHostBaseMediaRefreshOs(pThis);
938 if (RT_FAILURE(rc))
939 return rc;
940
941 /*
942 * Determine the size.
943 */
944 uint64_t cb;
945 rc = drvHostBaseGetMediaSizeOs(pThis, &cb);
946 if (RT_FAILURE(rc))
947 {
948 LogFlow(("%s-%d: failed to figure media size of %s, rc=%Rrc\n",
949 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
950 return rc;
951 }
952
953 /*
954 * Update the data and inform the unit.
955 */
956 pThis->cbSize = cb;
957 pThis->fMediaPresent = true;
958 if (pThis->pDrvMountNotify)
959 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
960 LogFlow(("%s-%d: drvHostBaseMediaPresent: cbSize=%lld (%#llx)\n",
961 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->cbSize, pThis->cbSize));
962 return VINF_SUCCESS;
963}
964
965
966/**
967 * Media no longer present.
968 * @param pThis The instance data.
969 */
970DECLHIDDEN(void) DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis)
971{
972 pThis->fMediaPresent = false;
973 pThis->fLocked = false;
974 pThis->PCHSGeometry.cCylinders = 0;
975 pThis->PCHSGeometry.cHeads = 0;
976 pThis->PCHSGeometry.cSectors = 0;
977 pThis->LCHSGeometry.cCylinders = 0;
978 pThis->LCHSGeometry.cHeads = 0;
979 pThis->LCHSGeometry.cSectors = 0;
980 if (pThis->pDrvMountNotify)
981 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
982}
983
984
985static int drvHostBaseMediaPoll(PDRVHOSTBASE pThis)
986{
987 /*
988 * Poll for media change.
989 */
990 bool fMediaPresent = false;
991 bool fMediaChanged = false;
992 drvHostBaseQueryMediaStatusOs(pThis, &fMediaChanged, &fMediaPresent);
993
994 RTCritSectEnter(&pThis->CritSect);
995
996 int rc = VINF_SUCCESS;
997 if (pThis->fMediaPresent != fMediaPresent)
998 {
999 LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));
1000 pThis->fMediaPresent = false;
1001 if (fMediaPresent)
1002 rc = DRVHostBaseMediaPresent(pThis);
1003 else
1004 DRVHostBaseMediaNotPresent(pThis);
1005 }
1006 else if (fMediaPresent)
1007 {
1008 /*
1009 * Poll for media change.
1010 */
1011 if (fMediaChanged)
1012 {
1013 LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
1014 DRVHostBaseMediaNotPresent(pThis);
1015 rc = DRVHostBaseMediaPresent(pThis);
1016 }
1017 }
1018
1019 RTCritSectLeave(&pThis->CritSect);
1020 return rc;
1021}
1022
1023
1024/**
1025 * This thread will periodically poll the device for media presence.
1026 *
1027 * @returns Ignored.
1028 * @param ThreadSelf Handle of this thread. Ignored.
1029 * @param pvUser Pointer to the driver instance structure.
1030 */
1031static DECLCALLBACK(int) drvHostBaseMediaThread(RTTHREAD ThreadSelf, void *pvUser)
1032{
1033 PDRVHOSTBASE pThis = (PDRVHOSTBASE)pvUser;
1034 LogFlow(("%s-%d: drvHostBaseMediaThread: ThreadSelf=%p pvUser=%p\n",
1035 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser));
1036 bool fFirst = true;
1037 int cRetries = 10;
1038 while (!pThis->fShutdownPoller)
1039 {
1040 /*
1041 * Perform the polling (unless we've run out of 50ms retries).
1042 */
1043 if (cRetries-- > 0)
1044 {
1045
1046 int rc = drvHostBaseMediaPoll(pThis);
1047 if (RT_FAILURE(rc))
1048 {
1049 RTSemEventWait(pThis->EventPoller, 50);
1050 continue;
1051 }
1052 }
1053
1054 /*
1055 * Signal EMT after the first go.
1056 */
1057 if (fFirst)
1058 {
1059 RTThreadUserSignal(ThreadSelf);
1060 fFirst = false;
1061 }
1062
1063 /*
1064 * Sleep.
1065 */
1066 int rc = RTSemEventWait(pThis->EventPoller, pThis->cMilliesPoller);
1067 if ( RT_FAILURE(rc)
1068 && rc != VERR_TIMEOUT)
1069 {
1070 AssertMsgFailed(("rc=%Rrc\n", rc));
1071 pThis->ThreadPoller = NIL_RTTHREAD;
1072 LogFlow(("drvHostBaseMediaThread: returns %Rrc\n", rc));
1073 return rc;
1074 }
1075 cRetries = 10;
1076 }
1077
1078 /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */
1079 LogFlow(("%s-%d: drvHostBaseMediaThread: returns VINF_SUCCESS\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
1080 return VINF_SUCCESS;
1081}
1082
1083/**
1084 * Registers statistics associated with the given media driver.
1085 *
1086 * @returns VBox status code.
1087 * @param pThis The media driver instance.
1088 */
1089static int drvHostBaseStatsRegister(PDRVHOSTBASE pThis)
1090{
1091 PPDMDRVINS pDrvIns = pThis->pDrvIns;
1092 uint32_t iInstance, iLUN;
1093 const char *pcszController;
1094
1095 int rc = pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, &pcszController,
1096 &iInstance, &iLUN);
1097 if (RT_SUCCESS(rc))
1098 {
1099 char *pszCtrlUpper = RTStrDup(pcszController);
1100 if (pszCtrlUpper)
1101 {
1102 RTStrToUpper(pszCtrlUpper);
1103
1104 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
1105 "Amount of data read.", "/Devices/%s%u/Port%u/ReadBytes", pszCtrlUpper, iInstance, iLUN);
1106 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
1107 "Amount of data written.", "/Devices/%s%u/Port%u/WrittenBytes", pszCtrlUpper, iInstance, iLUN);
1108
1109 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1110 "Number of I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsSubmitted", pszCtrlUpper, iInstance, iLUN);
1111 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1112 "Number of I/O requests failed.", "/Devices/%s%u/Port%u/ReqsFailed", pszCtrlUpper, iInstance, iLUN);
1113 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsSucceeded, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1114 "Number of I/O requests succeeded.", "/Devices/%s%u/Port%u/ReqsSucceeded", pszCtrlUpper, iInstance, iLUN);
1115 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsFlush, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1116 "Number of flush I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsFlush", pszCtrlUpper, iInstance, iLUN);
1117 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsWrite, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1118 "Number of write I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsWrite", pszCtrlUpper, iInstance, iLUN);
1119 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1120 "Number of read I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsRead", pszCtrlUpper, iInstance, iLUN);
1121
1122 RTStrFree(pszCtrlUpper);
1123 }
1124 else
1125 rc = VERR_NO_STR_MEMORY;
1126 }
1127
1128 return rc;
1129}
1130
1131/**
1132 * Deregisters statistics associated with the given media driver.
1133 *
1134 * @returns nothing.
1135 * @param pThis The media driver instance.
1136 */
1137static void drvhostBaseStatsDeregister(PDRVHOSTBASE pThis)
1138{
1139 PPDMDRVINS pDrvIns = pThis->pDrvIns;
1140
1141 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesRead);
1142 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesWritten);
1143 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsSubmitted);
1144 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsFailed);
1145 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsSucceeded);
1146 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsFlush);
1147 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsWrite);
1148 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsRead);
1149}
1150
1151/* -=-=-=-=- driver interface -=-=-=-=- */
1152
1153
1154/**
1155 * Done state load operation.
1156 *
1157 * @returns VBox load code.
1158 * @param pDrvIns Driver instance of the driver which registered the data unit.
1159 * @param pSSM SSM operation handle.
1160 */
1161static DECLCALLBACK(int) drvHostBaseLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1162{
1163 RT_NOREF(pSSM);
1164 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
1165 LogFlow(("%s-%d: drvHostBaseMediaThread:\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
1166 RTCritSectEnter(&pThis->CritSect);
1167
1168 /*
1169 * Tell the device/driver above us that the media status is uncertain.
1170 */
1171 if (pThis->pDrvMountNotify)
1172 {
1173 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
1174 if (pThis->fMediaPresent)
1175 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
1176 }
1177
1178 RTCritSectLeave(&pThis->CritSect);
1179 return VINF_SUCCESS;
1180}
1181
1182
1183/** @copydoc FNPDMDRVDESTRUCT */
1184DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns)
1185{
1186 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
1187 LogFlow(("%s-%d: drvHostBaseDestruct: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));
1188
1189 /*
1190 * Terminate the thread.
1191 */
1192 if (pThis->ThreadPoller != NIL_RTTHREAD)
1193 {
1194 pThis->fShutdownPoller = true;
1195 int rc;
1196 int cTimes = 50;
1197 do
1198 {
1199 RTSemEventSignal(pThis->EventPoller);
1200 rc = RTThreadWait(pThis->ThreadPoller, 100, NULL);
1201 } while (cTimes-- > 0 && rc == VERR_TIMEOUT);
1202
1203 if (!rc)
1204 pThis->ThreadPoller = NIL_RTTHREAD;
1205 }
1206
1207 /*
1208 * Cleanup the other resources.
1209 */
1210 drvHostBaseDestructOs(pThis);
1211
1212 if (pThis->EventPoller != NULL)
1213 {
1214 RTSemEventDestroy(pThis->EventPoller);
1215 pThis->EventPoller = NULL;
1216 }
1217
1218 if (pThis->pszDevice)
1219 {
1220 MMR3HeapFree(pThis->pszDevice);
1221 pThis->pszDevice = NULL;
1222 }
1223
1224 if (pThis->pszDeviceOpen)
1225 {
1226 RTStrFree(pThis->pszDeviceOpen);
1227 pThis->pszDeviceOpen = NULL;
1228 }
1229
1230 if (pThis->pvBuf)
1231 {
1232 RTMemFree(pThis->pvBuf);
1233 pThis->pvBuf = NULL;
1234 pThis->cbBuf = 0;
1235 }
1236
1237 /* Forget about the notifications. */
1238 pThis->pDrvMountNotify = NULL;
1239
1240 drvhostBaseStatsDeregister(pThis);
1241
1242 /* Leave the instance operational if this is just a cleanup of the state
1243 * after an attach error happened. So don't destroy the critsect then. */
1244 if (!pThis->fKeepInstance && RTCritSectIsInitialized(&pThis->CritSect))
1245 RTCritSectDelete(&pThis->CritSect);
1246 LogFlow(("%s-%d: drvHostBaseDestruct completed\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1247}
1248
1249
1250/**
1251 * Initializes the instance data .
1252 *
1253 * On failure call DRVHostBaseDestruct().
1254 *
1255 * @returns VBox status code.
1256 * @param pDrvIns Driver instance.
1257 * @param pszCfgValid Pointer to a string of valid CFGM options.
1258 * @param pCfg Configuration handle.
1259 * @param enmType Device type.
1260 */
1261DECLHIDDEN(int) DRVHostBaseInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType)
1262{
1263 int src = VINF_SUCCESS;
1264 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
1265 LogFlow(("%s-%d: DRVHostBaseInit: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));
1266
1267 /*
1268 * Initialize most of the data members.
1269 */
1270 pThis->pDrvIns = pDrvIns;
1271 pThis->fKeepInstance = false;
1272 pThis->ThreadPoller = NIL_RTTHREAD;
1273 pThis->enmType = enmType;
1274 pThis->fAttachFailError = true; /* It's an error until we've read the config. */
1275
1276 /* IBase. */
1277 pDrvIns->IBase.pfnQueryInterface = drvHostBaseQueryInterface;
1278
1279 /* IMedia. */
1280 pThis->IMedia.pfnRead = drvHostBaseRead;
1281 pThis->IMedia.pfnWrite = drvHostBaseWrite;
1282 pThis->IMedia.pfnFlush = drvHostBaseFlush;
1283 pThis->IMedia.pfnIsReadOnly = drvHostBaseIsReadOnly;
1284 pThis->IMedia.pfnIsNonRotational = drvHostBaseIsNonRotational;
1285 pThis->IMedia.pfnGetSize = drvHostBaseGetSize;
1286 pThis->IMedia.pfnGetType = drvHostBaseGetType;
1287 pThis->IMedia.pfnGetUuid = drvHostBaseGetUuid;
1288 pThis->IMedia.pfnBiosGetPCHSGeometry = drvHostBaseGetPCHSGeometry;
1289 pThis->IMedia.pfnBiosSetPCHSGeometry = drvHostBaseSetPCHSGeometry;
1290 pThis->IMedia.pfnBiosGetLCHSGeometry = drvHostBaseGetLCHSGeometry;
1291 pThis->IMedia.pfnBiosSetLCHSGeometry = drvHostBaseSetLCHSGeometry;
1292 pThis->IMedia.pfnBiosIsVisible = drvHostBaseIsVisible;
1293 pThis->IMedia.pfnGetRegionCount = drvHostBaseGetRegionCount;
1294 pThis->IMedia.pfnQueryRegionProperties = drvHostBaseQueryRegionProperties;
1295 pThis->IMedia.pfnQueryRegionPropertiesForLba = drvHostBaseQueryRegionPropertiesForLba;
1296
1297 /* IMediaEx */
1298 pThis->IMediaEx.pfnQueryFeatures = drvHostBaseQueryFeatures;
1299 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvHostBaseIoReqAllocSizeSet;
1300 pThis->IMediaEx.pfnIoReqAlloc = drvHostBaseIoReqAlloc;
1301 pThis->IMediaEx.pfnIoReqFree = drvHostBaseIoReqFree;
1302 pThis->IMediaEx.pfnIoReqQueryResidual = drvHostBaseIoReqQueryResidual;
1303 pThis->IMediaEx.pfnIoReqQueryXferSize = drvHostBaseIoReqQueryXferSize;
1304 pThis->IMediaEx.pfnIoReqCancelAll = drvHostBaseIoReqCancelAll;
1305 pThis->IMediaEx.pfnIoReqCancel = drvHostBaseIoReqCancel;
1306 pThis->IMediaEx.pfnIoReqRead = drvHostBaseIoReqRead;
1307 pThis->IMediaEx.pfnIoReqWrite = drvHostBaseIoReqWrite;
1308 pThis->IMediaEx.pfnIoReqFlush = drvHostBaseIoReqFlush;
1309 pThis->IMediaEx.pfnIoReqDiscard = drvHostBaseIoReqDiscard;
1310 pThis->IMediaEx.pfnIoReqGetActiveCount = drvHostBaseIoReqGetActiveCount;
1311 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvHostBaseIoReqGetSuspendedCount;
1312 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvHostBaseIoReqQuerySuspendedStart;
1313 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvHostBaseIoReqQuerySuspendedNext;
1314 pThis->IMediaEx.pfnIoReqSuspendedSave = drvHostBaseIoReqSuspendedSave;
1315 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvHostBaseIoReqSuspendedLoad;
1316
1317 /* IMount. */
1318 pThis->IMount.pfnUnmount = drvHostBaseUnmount;
1319 pThis->IMount.pfnIsMounted = drvHostBaseIsMounted;
1320 pThis->IMount.pfnLock = drvHostBaseLock;
1321 pThis->IMount.pfnUnlock = drvHostBaseUnlock;
1322 pThis->IMount.pfnIsLocked = drvHostBaseIsLocked;
1323
1324 drvHostBaseInitOs(pThis);
1325
1326 if (!CFGMR3AreValuesValid(pCfg, pszCfgValid))
1327 {
1328 pThis->fAttachFailError = true;
1329 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1330 }
1331
1332 /*
1333 * Get the IMediaPort & IMountNotify interfaces of the above driver/device.
1334 */
1335 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1336 if (!pThis->pDrvMediaPort)
1337 {
1338 AssertMsgFailed(("Configuration error: No media port interface above!\n"));
1339 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1340 }
1341 pThis->pDrvMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1342 pThis->pDrvMountNotify = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMOUNTNOTIFY);
1343
1344 /*
1345 * Query configuration.
1346 */
1347 /* Device */
1348 int rc = CFGMR3QueryStringAlloc(pCfg, "Path", &pThis->pszDevice);
1349 if (RT_FAILURE(rc))
1350 {
1351 AssertMsgFailed(("Configuration error: query for \"Path\" string returned %Rra.\n", rc));
1352 return rc;
1353 }
1354
1355 /* Mountable */
1356 uint32_t u32;
1357 rc = CFGMR3QueryU32Def(pCfg, "Interval", &u32, 1000);
1358 if (RT_SUCCESS(rc))
1359 pThis->cMilliesPoller = u32;
1360 else
1361 {
1362 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Rrc.\n", rc));
1363 return rc;
1364 }
1365
1366 /* ReadOnly - passthrough mode requires read/write access in any case. */
1367 if ( (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
1368 && pThis->IMedia.pfnSendCmd)
1369 pThis->fReadOnlyConfig = false;
1370 else
1371 {
1372 rc = CFGMR3QueryBoolDef(pCfg, "ReadOnly", &pThis->fReadOnlyConfig,
1373 enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM
1374 ? true
1375 : false);
1376 if (RT_FAILURE(rc))
1377 {
1378 AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Rrc.\n", rc));
1379 return rc;
1380 }
1381 }
1382
1383 /* Locked */
1384 rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false);
1385 if (RT_FAILURE(rc))
1386 {
1387 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Rrc.\n", rc));
1388 return rc;
1389 }
1390
1391 /* BIOS visible */
1392 rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true);
1393 if (RT_FAILURE(rc))
1394 {
1395 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Rrc.\n", rc));
1396 return rc;
1397 }
1398
1399 /* Uuid */
1400 char *psz;
1401 rc = CFGMR3QueryStringAlloc(pCfg, "Uuid", &psz);
1402 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1403 RTUuidClear(&pThis->Uuid);
1404 else if (RT_SUCCESS(rc))
1405 {
1406 rc = RTUuidFromStr(&pThis->Uuid, psz);
1407 if (RT_FAILURE(rc))
1408 {
1409 AssertMsgFailed(("Configuration error: Uuid from string failed on \"%s\", rc=%Rrc.\n", psz, rc));
1410 MMR3HeapFree(psz);
1411 return rc;
1412 }
1413 MMR3HeapFree(psz);
1414 }
1415 else
1416 {
1417 AssertMsgFailed(("Configuration error: Failed to obtain the uuid, rc=%Rrc.\n", rc));
1418 return rc;
1419 }
1420
1421 /* Define whether attach failure is an error (default) or not. */
1422 bool fAttachFailError = true;
1423 rc = CFGMR3QueryBoolDef(pCfg, "AttachFailError", &fAttachFailError, true);
1424 pThis->fAttachFailError = fAttachFailError;
1425
1426 /* log config summary */
1427 Log(("%s-%d: pszDevice='%s' (%s) cMilliesPoller=%d fReadOnlyConfig=%d fLocked=%d fBIOSVisible=%d Uuid=%RTuuid\n",
1428 pDrvIns->pReg->szName, pDrvIns->iInstance, pThis->pszDevice, pThis->pszDeviceOpen, pThis->cMilliesPoller,
1429 pThis->fReadOnlyConfig, pThis->fLocked, pThis->fBiosVisible, &pThis->Uuid));
1430
1431 /*
1432 * Check that there are no drivers below us.
1433 */
1434 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1435 ("Configuration error: Not possible to attach anything to this driver!\n"),
1436 VERR_PDM_DRVINS_NO_ATTACH);
1437
1438 /*
1439 * Register saved state.
1440 */
1441 rc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, drvHostBaseLoadDone);
1442 if (RT_FAILURE(rc))
1443 return rc;
1444
1445 /*
1446 * Initialize the critical section used for serializing the access to the media.
1447 */
1448 rc = RTCritSectInit(&pThis->CritSect);
1449 if (RT_FAILURE(rc))
1450 return rc;
1451
1452 /*
1453 * Open the device.
1454 */
1455 rc = drvHostBaseOpenOs(pThis, pThis->fReadOnlyConfig);
1456 if (RT_FAILURE(rc))
1457 {
1458 char *pszDevice = pThis->pszDevice;
1459#ifndef RT_OS_DARWIN
1460 char szPathReal[256];
1461 if ( RTPathExists(pszDevice)
1462 && RT_SUCCESS(RTPathReal(pszDevice, szPathReal, sizeof(szPathReal))))
1463 pszDevice = szPathReal;
1464#endif
1465
1466 /*
1467 * Disable CD/DVD passthrough in case it was enabled. Would cause
1468 * weird failures later when the guest issues commands. These would
1469 * all fail because of the invalid file handle. So use the normal
1470 * virtual CD/DVD code, which deals more gracefully with unavailable
1471 * "media" - actually a complete drive in this case.
1472 */
1473 pThis->IMedia.pfnSendCmd = NULL;
1474 AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pszDevice, rc));
1475 switch (rc)
1476 {
1477 case VERR_ACCESS_DENIED:
1478 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1479#ifdef RT_OS_LINUX
1480 N_("Cannot open host device '%s' for %s access. Check the permissions "
1481 "of that device ('/bin/ls -l %s'): Most probably you need to be member "
1482 "of the device group. Make sure that you logout/login after changing "
1483 "the group settings of the current user"),
1484#else
1485 N_("Cannot open host device '%s' for %s access. Check the permissions "
1486 "of that device"),
1487#endif
1488 pszDevice, pThis->fReadOnlyConfig ? "readonly" : "read/write",
1489 pszDevice);
1490 default:
1491 {
1492 if (pThis->fAttachFailError)
1493 return rc;
1494 int erc = PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/,
1495 "DrvHost_MOUNTFAIL",
1496 N_("Cannot attach to host device '%s'"), pszDevice);
1497 AssertRC(erc);
1498 src = rc;
1499 }
1500 }
1501 }
1502
1503 /*
1504 * Lock the drive if that's required by the configuration.
1505 */
1506 if (pThis->fLocked)
1507 {
1508 if (pThis->pfnDoLock)
1509 rc = pThis->pfnDoLock(pThis, true);
1510 if (RT_FAILURE(rc))
1511 {
1512 AssertMsgFailed(("Failed to lock the dvd drive. rc=%Rrc\n", rc));
1513 return rc;
1514 }
1515 }
1516
1517 if (RT_SUCCESS(src) && drvHostBaseIsMediaPollingRequiredOs(pThis))
1518 {
1519 /*
1520 * Create the event semaphore which the poller thread will wait on.
1521 */
1522 rc = RTSemEventCreate(&pThis->EventPoller);
1523 if (RT_FAILURE(rc))
1524 return rc;
1525
1526 /*
1527 * Start the thread which will poll for the media.
1528 */
1529 rc = RTThreadCreate(&pThis->ThreadPoller, drvHostBaseMediaThread, pThis, 0,
1530 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
1531 if (RT_FAILURE(rc))
1532 {
1533 AssertMsgFailed(("Failed to create poller thread. rc=%Rrc\n", rc));
1534 return rc;
1535 }
1536
1537 /*
1538 * Wait for the thread to start up (!w32:) and do one detection loop.
1539 */
1540 rc = RTThreadUserWait(pThis->ThreadPoller, 10000);
1541 AssertRC(rc);
1542 }
1543
1544 if (RT_SUCCESS(rc))
1545 drvHostBaseStatsRegister(pThis);
1546
1547 if (RT_FAILURE(rc))
1548 {
1549 if (!pThis->fAttachFailError)
1550 {
1551 /* Suppressing the attach failure error must not affect the normal
1552 * DRVHostBaseDestruct, so reset this flag below before leaving. */
1553 pThis->fKeepInstance = true;
1554 rc = VINF_SUCCESS;
1555 }
1556 DRVHostBaseDestruct(pDrvIns);
1557 pThis->fKeepInstance = false;
1558 }
1559
1560 if (RT_FAILURE(src))
1561 return src;
1562
1563 return rc;
1564}
1565
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