VirtualBox

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

Last change on this file since 103882 was 99739, checked in by vboxsync, 13 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use