VirtualBox

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

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

Devices/Storage: Forgot to commit files

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