VirtualBox

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

Last change on this file since 92226 was 92226, checked in by vboxsync, 3 years ago

Devices/DrvHostBase.cpp: Mark drives as locked only if it actually supports locking (host floppies don't).

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