VirtualBox

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

Last change on this file since 64671 was 64407, checked in by vboxsync, 8 years ago

Devices/Storage: Add callback to query the actual transfer size of an I/O request if PDMIMEDIAEX is used, useful to calculate the amount of data transferred for requests where the transfer size can be different from the guest buffer size (e.g. SCSI)

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