VirtualBox

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

Last change on this file since 69496 was 69496, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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