VirtualBox

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

Last change on this file since 125 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.4 KB
Line 
1/** @file
2 *
3 * VBox storage devices:
4 * Host base drive access driver
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
28#ifdef __LINUX__
29# include <sys/ioctl.h>
30# include <sys/fcntl.h>
31# include <errno.h>
32
33#elif defined(__WIN__)
34# define WIN32_NO_STATUS
35# include <Windows.h>
36# include <dbt.h>
37# undef WIN32_NO_STATUS
38# include <ntstatus.h>
39
40/* from ntdef.h */
41typedef LONG NTSTATUS;
42
43/* from ntddk.h */
44typedef struct _IO_STATUS_BLOCK {
45 union {
46 NTSTATUS Status;
47 PVOID Pointer;
48 };
49 ULONG_PTR Information;
50} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
51
52
53/* from ntinternals.com */
54typedef enum _FS_INFORMATION_CLASS {
55 FileFsVolumeInformation=1,
56 FileFsLabelInformation,
57 FileFsSizeInformation,
58 FileFsDeviceInformation,
59 FileFsAttributeInformation,
60 FileFsControlInformation,
61 FileFsFullSizeInformation,
62 FileFsObjectIdInformation,
63 FileFsMaximumInformation
64} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
65
66typedef struct _FILE_FS_SIZE_INFORMATION {
67 LARGE_INTEGER TotalAllocationUnits;
68 LARGE_INTEGER AvailableAllocationUnits;
69 ULONG SectorsPerAllocationUnit;
70 ULONG BytesPerSector;
71} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
72
73extern "C"
74NTSTATUS __stdcall NtQueryVolumeInformationFile(
75 /*IN*/ HANDLE FileHandle,
76 /*OUT*/ PIO_STATUS_BLOCK IoStatusBlock,
77 /*OUT*/ PVOID FileSystemInformation,
78 /*IN*/ ULONG Length,
79 /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );
80
81#elif defined(__L4ENV__)
82
83#else /* !__WIN__ nor __LINUX__ nor __L4ENV__ */
84# error "Unsupported Platform."
85#endif /* !__WIN__ nor __LINUX__ nor __L4ENV__ */
86
87#include <VBox/pdm.h>
88#include <VBox/cfgm.h>
89#include <VBox/mm.h>
90#include <VBox/err.h>
91
92#include <VBox/log.h>
93#include <iprt/assert.h>
94#include <iprt/file.h>
95#include <iprt/string.h>
96#include <iprt/thread.h>
97#include <iprt/semaphore.h>
98#include <iprt/uuid.h>
99#include <iprt/asm.h>
100#include <iprt/critsect.h>
101
102#include "DrvHostBase.h"
103
104
105
106
107/* -=-=-=-=- IBlock -=-=-=-=- */
108
109/** @copydoc PDMIBLOCK::pfnRead */
110static DECLCALLBACK(int) drvHostBaseRead(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
111{
112 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
113 LogFlow(("%s-%d: drvHostBaseRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n",
114 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, off, pvBuf, cbRead, pThis->pszDevice));
115 RTCritSectEnter(&pThis->CritSect);
116
117 /*
118 * Check the state.
119 */
120 int rc;
121 if (pThis->fMediaPresent)
122 {
123 /*
124 * Seek and read.
125 */
126 rc = RTFileSeek(pThis->FileDevice, off, RTFILE_SEEK_BEGIN, NULL);
127 if (VBOX_SUCCESS(rc))
128 {
129 rc = RTFileRead(pThis->FileDevice, pvBuf, cbRead, NULL);
130 if (VBOX_SUCCESS(rc))
131 {
132 Log2(("%s-%d: drvHostBaseRead: off=%#llx cbRead=%#x\n"
133 "%16.*Vhxd\n",
134 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, off, cbRead, cbRead, pvBuf));
135 }
136 else
137 Log(("%s-%d: drvHostBaseRead: RTFileRead(%d, %p, %#x) -> %Vrc (off=%#llx '%s')\n",
138 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->FileDevice,
139 pvBuf, cbRead, rc, off, pThis->pszDevice));
140 }
141 else
142 Log(("%s-%d: drvHostBaseRead: RTFileSeek(%d,%#llx,) -> %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName,
143 pThis->pDrvIns->iInstance, pThis->FileDevice, off, rc));
144 }
145 else
146 rc = VERR_MEDIA_NOT_PRESENT;
147
148 RTCritSectLeave(&pThis->CritSect);
149 LogFlow(("%s-%d: drvHostBaseRead: returns %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc));
150 return rc;
151}
152
153
154/** @copydoc PDMIBLOCK::pfnWrite */
155static DECLCALLBACK(int) drvHostBaseWrite(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
156{
157 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
158 LogFlow(("%s-%d: drvHostBaseWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n",
159 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, off, pvBuf, cbWrite, pThis->pszDevice));
160 Log2(("%s-%d: drvHostBaseWrite: off=%#llx cbWrite=%#x\n"
161 "%16.*Vhxd\n",
162 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, off, cbWrite, cbWrite, pvBuf));
163 RTCritSectEnter(&pThis->CritSect);
164
165 /*
166 * Check the state.
167 */
168 int rc;
169 if (!pThis->fReadOnly)
170 {
171 if (pThis->fMediaPresent)
172 {
173 /*
174 * Seek and write.
175 */
176 rc = RTFileSeek(pThis->FileDevice, off, RTFILE_SEEK_BEGIN, NULL);
177 if (VBOX_SUCCESS(rc))
178 {
179 rc = RTFileWrite(pThis->FileDevice, pvBuf, cbWrite, NULL);
180 if (VBOX_FAILURE(rc))
181 Log(("%s-%d: drvHostBaseWrite: RTFileWrite(%d, %p, %#x) -> %Vrc (off=%#llx '%s')\n",
182 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->FileDevice,
183 pvBuf, cbWrite, rc, off, pThis->pszDevice));
184 }
185 else
186 Log(("%s-%d: drvHostBaseWrite: RTFileSeek(%d,%#llx,) -> %Vrc\n",
187 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->FileDevice, off, rc));
188 }
189 else
190 rc = VERR_MEDIA_NOT_PRESENT;
191 }
192 else
193 rc = VERR_WRITE_PROTECT;
194
195 RTCritSectLeave(&pThis->CritSect);
196 LogFlow(("%s-%d: drvHostBaseWrite: returns %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc));
197 return rc;
198}
199
200
201/** @copydoc PDMIBLOCK::pfnFlush */
202static DECLCALLBACK(int) drvHostBaseFlush(PPDMIBLOCK pInterface)
203{
204 int rc;
205 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
206 LogFlow(("%s-%d: drvHostBaseFlush: (%s)\n",
207 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->pszDevice));
208 RTCritSectEnter(&pThis->CritSect);
209
210 if (pThis->fMediaPresent)
211 {
212 rc = RTFileFlush(pThis->FileDevice);
213 }
214 else
215 rc = VERR_MEDIA_NOT_PRESENT;
216
217 RTCritSectLeave(&pThis->CritSect);
218 LogFlow(("%s-%d: drvHostBaseFlush: returns %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc));
219 return rc;
220}
221
222
223/** @copydoc PDMIBLOCK::pfnIsReadOnly */
224static DECLCALLBACK(bool) drvHostBaseIsReadOnly(PPDMIBLOCK pInterface)
225{
226 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
227 return pThis->fReadOnly;
228}
229
230
231/** @copydoc PDMIBLOCK::pfnGetSize */
232static DECLCALLBACK(uint64_t) drvHostBaseGetSize(PPDMIBLOCK pInterface)
233{
234 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
235 RTCritSectEnter(&pThis->CritSect);
236
237 uint64_t cb = 0;
238 if (pThis->fMediaPresent)
239 cb = pThis->cbSize;
240
241 RTCritSectLeave(&pThis->CritSect);
242 LogFlow(("%s-%d: drvHostBaseGetSize: returns %llu\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, cb));
243 return cb;
244}
245
246
247/** @copydoc PDMIBLOCK::pfnGetType */
248static DECLCALLBACK(PDMBLOCKTYPE) drvHostBaseGetType(PPDMIBLOCK pInterface)
249{
250 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
251 LogFlow(("%s-%d: drvHostBaseGetType: returns %d\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->enmType));
252 return pThis->enmType;
253}
254
255
256/** @copydoc PDMIBLOCK::pfnGetUuid */
257static DECLCALLBACK(int) drvHostBaseGetUuid(PPDMIBLOCK pInterface, PRTUUID pUuid)
258{
259 PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
260
261 *pUuid = pThis->Uuid;
262
263 LogFlow(("%s-%d: drvHostBaseGetUuid: returns VINF_SUCCESS *pUuid=%Vuuid\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pUuid));
264 return VINF_SUCCESS;
265}
266
267
268/* -=-=-=-=- IBlockBios -=-=-=-=- */
269
270/** Makes a PDRVHOSTBASE out of a PPDMIBLOCKBIOS. */
271#define PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface) ( (PDRVHOSTBASE((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTBASE, IBlockBios))) )
272
273
274/** @copydoc PDMIBLOCKBIOS::pfnGetGeometry */
275static DECLCALLBACK(int) drvHostBaseGetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
276{
277 PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
278 RTCritSectEnter(&pThis->CritSect);
279
280 int rc = VINF_SUCCESS;
281 if (pThis->fMediaPresent)
282 {
283 if ( pThis->cCylinders > 0
284 && pThis->cHeads > 0
285 && pThis->cSectors > 0)
286 {
287 *pcCylinders = pThis->cCylinders;
288 *pcHeads = pThis->cHeads;
289 *pcSectors = pThis->cSectors;
290 }
291 else
292 rc = VERR_PDM_GEOMETRY_NOT_SET;
293 }
294 else
295 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
296
297 RTCritSectLeave(&pThis->CritSect);
298 LogFlow(("%s-%d: drvHostBaseGetGeometry: returns %Vrc CHS={%d,%d,%d}\n",
299 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc, *pcCylinders, *pcHeads, *pcSectors));
300 return rc;
301}
302
303
304/** @copydoc PDMIBLOCKBIOS::pfnSetGeometry */
305static DECLCALLBACK(int) drvHostBaseSetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
306{
307 PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
308 LogFlow(("%s-%d: drvHostBaseSetGeometry: cCylinders=%d cHeads=%d cSectors=%d\n",
309 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, cCylinders, cHeads, cSectors));
310 RTCritSectEnter(&pThis->CritSect);
311
312 int rc = VINF_SUCCESS;
313 if (pThis->fMediaPresent)
314 {
315 pThis->cCylinders = cCylinders;
316 pThis->cHeads = cHeads;
317 pThis->cSectors = cSectors;
318 }
319 else
320 {
321 AssertMsgFailed(("Invalid state! Not mounted!\n"));
322 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
323 }
324
325 RTCritSectLeave(&pThis->CritSect);
326 return rc;
327}
328
329
330/** @copydoc PDMIBLOCKBIOS::pfnGetTranslation */
331static DECLCALLBACK(int) drvHostBaseGetTranslation(PPDMIBLOCKBIOS pInterface, PPDMBIOSTRANSLATION penmTranslation)
332{
333 PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
334 RTCritSectEnter(&pThis->CritSect);
335
336 int rc = VINF_SUCCESS;
337 if (pThis->fMediaPresent)
338 {
339 if (pThis->fTranslationSet)
340 *penmTranslation = pThis->enmTranslation;
341 else
342 rc = VERR_PDM_TRANSLATION_NOT_SET;
343 }
344 else
345 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
346
347 RTCritSectLeave(&pThis->CritSect);
348 LogFlow(("%s-%d: drvHostBaseGetTranslation: returns %Vrc *penmTranslation=%d\n",
349 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc, *penmTranslation));
350 return rc;
351}
352
353
354/** @copydoc PDMIBLOCKBIOS::pfnSetTranslation */
355static DECLCALLBACK(int) drvHostBaseSetTranslation(PPDMIBLOCKBIOS pInterface, PDMBIOSTRANSLATION enmTranslation)
356{
357 PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
358 LogFlow(("%s-%d: drvHostBaseSetTranslation: enmTranslation=%d\n",
359 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, enmTranslation));
360 RTCritSectEnter(&pThis->CritSect);
361
362 int rc = VINF_SUCCESS;
363 if (pThis->fMediaPresent)
364 {
365 pThis->fTranslationSet = true;
366 pThis->enmTranslation = enmTranslation;
367 }
368 else
369 {
370 AssertMsgFailed(("Invalid state! Not mounted!\n"));
371 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
372 }
373
374 RTCritSectLeave(&pThis->CritSect);
375 return rc;
376}
377
378
379/** @copydoc PDMIBLOCKBIOS::pfnIsVisible */
380static DECLCALLBACK(bool) drvHostBaseIsVisible(PPDMIBLOCKBIOS pInterface)
381{
382 PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
383 return pThis->fBiosVisible;
384}
385
386
387/** @copydoc PDMIBLOCKBIOS::pfnGetType */
388static DECLCALLBACK(PDMBLOCKTYPE) drvHostBaseBiosGetType(PPDMIBLOCKBIOS pInterface)
389{
390 PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
391 return pThis->enmType;
392}
393
394
395
396/* -=-=-=-=- IMount -=-=-=-=- */
397
398/** @copydoc PDMIMOUNT::pfnMount */
399static DECLCALLBACK(int) drvHostBaseMount(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)
400{
401 /* We're not mountable. */
402 AssertMsgFailed(("drvHostBaseMount: This shouldn't be called!\n"));
403 return VERR_PDM_MEDIA_MOUNTED;
404}
405
406
407/** @copydoc PDMIMOUNT::pfnUnmount */
408static DECLCALLBACK(int) drvHostBaseUnmount(PPDMIMOUNT pInterface)
409{
410 LogFlow(("drvHostBaseUnmount: returns VERR_NOT_SUPPORTED\n"));
411 return VERR_NOT_SUPPORTED;
412}
413
414
415/** @copydoc PDMIMOUNT::pfnIsMounted */
416static DECLCALLBACK(bool) drvHostBaseIsMounted(PPDMIMOUNT pInterface)
417{
418 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
419 RTCritSectEnter(&pThis->CritSect);
420
421 bool fRc = pThis->fMediaPresent;
422
423 RTCritSectLeave(&pThis->CritSect);
424 return fRc;
425}
426
427
428/** @copydoc PDMIMOUNT::pfnIsLocked */
429static DECLCALLBACK(int) drvHostBaseLock(PPDMIMOUNT pInterface)
430{
431 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
432 RTCritSectEnter(&pThis->CritSect);
433
434 int rc = VINF_SUCCESS;
435 if (!pThis->fLocked)
436 {
437 if (pThis->pfnDoLock)
438 rc = pThis->pfnDoLock(pThis, true);
439 if (VBOX_SUCCESS(rc))
440 pThis->fLocked = true;
441 }
442 else
443 LogFlow(("%s-%d: drvHostBaseLock: already locked\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance));
444
445 RTCritSectLeave(&pThis->CritSect);
446 LogFlow(("%s-%d: drvHostBaseLock: returns %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc));
447 return rc;
448}
449
450
451/** @copydoc PDMIMOUNT::pfnIsLocked */
452static DECLCALLBACK(int) drvHostBaseUnlock(PPDMIMOUNT pInterface)
453{
454 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
455 RTCritSectEnter(&pThis->CritSect);
456
457 int rc = VINF_SUCCESS;
458 if (pThis->fLocked)
459 {
460 if (pThis->pfnDoLock)
461 rc = pThis->pfnDoLock(pThis, false);
462 if (VBOX_SUCCESS(rc))
463 pThis->fLocked = false;
464 }
465 else
466 LogFlow(("%s-%d: drvHostBaseUnlock: not locked\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance));
467
468 RTCritSectLeave(&pThis->CritSect);
469 LogFlow(("%s-%d: drvHostBaseUnlock: returns %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc));
470 return rc;
471}
472
473
474/** @copydoc PDMIMOUNT::pfnIsLocked */
475static DECLCALLBACK(bool) drvHostBaseIsLocked(PPDMIMOUNT pInterface)
476{
477 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
478 RTCritSectEnter(&pThis->CritSect);
479
480 bool fRc = pThis->fLocked;
481
482 RTCritSectLeave(&pThis->CritSect);
483 return fRc;
484}
485
486
487/* -=-=-=-=- IBase -=-=-=-=- */
488
489/** @copydoc PDMIBASE::pfnQueryInterface. */
490static DECLCALLBACK(void *) drvHostBaseQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
491{
492 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
493 PDRVHOSTBASE pThis = PDMINS2DATA(pDrvIns, PDRVHOSTBASE);
494 switch (enmInterface)
495 {
496 case PDMINTERFACE_BASE:
497 return &pDrvIns->IBase;
498 case PDMINTERFACE_BLOCK:
499 return &pThis->IBlock;
500 case PDMINTERFACE_BLOCK_BIOS:
501 return pThis->fBiosVisible ? &pThis->IBlockBios : NULL;
502 case PDMINTERFACE_MOUNT:
503 return &pThis->IMount;
504 default:
505 return NULL;
506 }
507}
508
509
510/* -=-=-=-=- poller thread -=-=-=-=- */
511
512/**
513 * Wrapper for open / RTFileOpen.
514 */
515static int drvHostBaseOpen(PDRVHOSTBASE pThis, PRTFILE pFileDevice, bool fReadOnly)
516{
517#ifdef __LINUX__
518 int FileDevice = open(pThis->pszDeviceOpen, (pThis->fReadOnlyConfig ? O_RDONLY : O_RDWR) | O_NONBLOCK);
519 if (FileDevice < 0)
520 return RTErrConvertFromErrno(errno);
521 *pFileDevice = FileDevice;
522 return VINF_SUCCESS;
523#else
524 return RTFileOpen(pFileDevice, pThis->pszDeviceOpen,
525 (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
526#endif
527}
528
529/**
530 * (Re)opens the device.
531 *
532 * @returns VBOX status code.
533 * @param pThis Instance data.
534 */
535static int drvHostBaseReopen(PDRVHOSTBASE pThis)
536{
537 LogFlow(("%s-%d: drvHostBaseReopen: '%s'\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen));
538
539 /*
540 * Reopen the device to kill any cached data which for some peculiar reason stays on some OSes (linux)...
541 */
542 RTFILE FileDevice;
543 int rc = drvHostBaseOpen(pThis, &FileDevice, pThis->fReadOnlyConfig);
544 if (VBOX_FAILURE(rc))
545 {
546 if (!pThis->fReadOnlyConfig)
547 {
548 LogFlow(("%s-%d: drvHostBaseReopen: '%s' - retry readonly (%Vrc)\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen, rc));
549 rc = drvHostBaseOpen(pThis, &FileDevice, false);
550 }
551 if (VBOX_FAILURE(rc))
552 {
553 LogFlow(("%s-%d: failed to open device '%s', rc=%Vrc\n",
554 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
555 return rc;
556 }
557 pThis->fReadOnly = true;
558 }
559 else
560 pThis->fReadOnly = pThis->fReadOnlyConfig;
561
562 if (pThis->FileDevice != NIL_RTFILE)
563 RTFileClose(pThis->FileDevice);
564 pThis->FileDevice = FileDevice;
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * Queries the media size.
571 *
572 * @returns VBox status code.
573 * @param pThis Pointer to the instance data.
574 * @param pcb Where to store the media size in bytes.
575 */
576static int drvHostBaseGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
577{
578#ifdef __WIN__
579 /* use NT api, retry a few times if the media is being verified. */
580 IO_STATUS_BLOCK IoStatusBlock = {0};
581 FILE_FS_SIZE_INFORMATION FsSize= {0};
582 NTSTATUS rcNt = NtQueryVolumeInformationFile((HANDLE)pThis->FileDevice, &IoStatusBlock,
583 &FsSize, sizeof(FsSize), FileFsSizeInformation);
584 int cRetries = 5;
585 while (rcNt == STATUS_VERIFY_REQUIRED && cRetries-- > 0)
586 {
587 RTThreadSleep(10);
588 rcNt = NtQueryVolumeInformationFile((HANDLE)pThis->FileDevice, &IoStatusBlock,
589 &FsSize, sizeof(FsSize), FileFsSizeInformation);
590 }
591 if (rcNt >= 0)
592 {
593 *pcb = FsSize.TotalAllocationUnits.QuadPart * FsSize.BytesPerSector;
594 return VINF_SUCCESS;
595 }
596
597 /* convert nt status code to VBox status code. */
598 /** @todo Make convertion function!. */
599 int rc = VERR_GENERAL_FAILURE;
600 switch (rcNt)
601 {
602 case STATUS_NO_MEDIA_IN_DEVICE: rc = VERR_MEDIA_NOT_PRESENT; break;
603 case STATUS_VERIFY_REQUIRED: rc = VERR_TRY_AGAIN; break;
604 }
605 LogFlow(("drvHostBaseGetMediaSize: NtQueryVolumeInformationFile -> %#lx\n", rcNt, rc));
606 return rc;
607#else
608 return RTFileSeek(pThis->FileDevice, 0, RTFILE_SEEK_END, pcb);
609#endif
610}
611
612
613/**
614 * Media present.
615 * Query the size and notify the above driver / device.
616 *
617 * @param pThis The instance data.
618 */
619int DRVHostBaseMediaPresent(PDRVHOSTBASE pThis)
620{
621 /*
622 * Open the drive.
623 */
624 int rc = drvHostBaseReopen(pThis);
625 if (VBOX_FAILURE(rc))
626 return rc;
627
628 /*
629 * Determin the size.
630 */
631 uint64_t cb;
632 rc = pThis->pfnGetMediaSize(pThis, &cb);
633 if (VBOX_FAILURE(rc))
634 {
635 LogFlow(("%s-%d: failed to figure media size of %s, rc=%Vrc\n",
636 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
637 return rc;
638 }
639
640 /*
641 * Update the data and inform the unit.
642 */
643 pThis->cbSize = cb;
644 pThis->fMediaPresent = true;
645 if (pThis->pDrvMountNotify)
646 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
647 LogFlow(("%s-%d: drvHostBaseMediaPresent: cbSize=%lld (%#llx)\n",
648 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->cbSize, pThis->cbSize));
649 return VINF_SUCCESS;
650}
651
652
653/**
654 * Media no longer present.
655 * @param pThis The instance data.
656 */
657void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis)
658{
659 pThis->fMediaPresent = false;
660 pThis->fLocked = false;
661 pThis->fTranslationSet = false;
662 pThis->cSectors = 0;
663 if (pThis->pDrvMountNotify)
664 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
665}
666
667
668#ifdef __WIN__
669
670/**
671 * Window procedure for the invisible window used to catch the WM_DEVICECHANGE broadcasts.
672 */
673static LRESULT CALLBACK DeviceChangeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
674{
675 Log2(("DeviceChangeWindowProc: hwnd=%08x uMsg=%08x\n", hwnd, uMsg));
676 if (uMsg == WM_DESTROY)
677 {
678 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLong(hwnd, GWLP_USERDATA);
679 if (pThis)
680 ASMAtomicXchgSize(&pThis->hwndDeviceChange, NULL);
681 PostQuitMessage(0);
682 }
683
684 if (uMsg != WM_DEVICECHANGE)
685 return DefWindowProc(hwnd, uMsg, wParam, lParam);
686
687 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
688 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
689 Assert(pThis);
690 if (pThis == NULL)
691 return 0;
692
693 switch (wParam)
694 {
695 case DBT_DEVICEARRIVAL:
696 case DBT_DEVICEREMOVECOMPLETE:
697 // Check whether a CD or DVD was inserted into or removed from a drive.
698 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
699 {
700 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
701 if ( (lpdbv->dbcv_flags & DBTF_MEDIA)
702 && (pThis->fUnitMask & lpdbv->dbcv_unitmask))
703 {
704 RTCritSectEnter(&pThis->CritSect);
705 if (wParam == DBT_DEVICEARRIVAL)
706 {
707 int cRetries = 10;
708 int rc = DRVHostBaseMediaPresent(pThis);
709 while (VBOX_FAILURE(rc) && cRetries-- > 0)
710 {
711 RTThreadSleep(50);
712 rc = DRVHostBaseMediaPresent(pThis);
713 }
714 }
715 else
716 DRVHostBaseMediaNotPresent(pThis);
717 RTCritSectLeave(&pThis->CritSect);
718 }
719 }
720 break;
721 }
722 return TRUE;
723}
724
725#endif /* __WIN__ */
726
727
728/**
729 * This thread will periodically poll the device for media presence.
730 *
731 * @returns Ignored.
732 * @param ThreadSelf Handle of this thread. Ignored.
733 * @param pvUser Pointer to the driver instance structure.
734 */
735static DECLCALLBACK(int) drvHostBaseMediaThread(RTTHREAD ThreadSelf, void *pvUser)
736{
737 PDRVHOSTBASE pThis = (PDRVHOSTBASE)pvUser;
738 LogFlow(("%s-%d: drvHostBaseMediaThread: ThreadSelf=%p pvUser=%p\n",
739 pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser));
740#ifdef __WIN__
741 static WNDCLASS s_classDeviceChange = {0};
742 static ATOM s_hAtomDeviceChange = 0;
743
744 /*
745 * Register custom window class.
746 */
747 if (s_hAtomDeviceChange == 0)
748 {
749 memset(&s_classDeviceChange, 0, sizeof(s_classDeviceChange));
750 s_classDeviceChange.lpfnWndProc = DeviceChangeWindowProc;
751 s_classDeviceChange.lpszClassName = "VBOX_DeviceChangeClass";
752 s_classDeviceChange.hInstance = GetModuleHandle("VBOXDD.DLL");
753 Assert(s_classDeviceChange.hInstance);
754 s_hAtomDeviceChange = RegisterClassA(&s_classDeviceChange);
755 Assert(s_hAtomDeviceChange);
756 }
757
758 /*
759 * Create Window w/ the pThis as user data.
760 */
761 HWND hwnd = CreateWindow((LPCTSTR)s_hAtomDeviceChange, "", WS_POPUP, 0, 0, 0, 0, 0, 0, s_classDeviceChange.hInstance, 0);
762 AssertMsg(hwnd, ("CreateWindow failed with %d\n", GetLastError()));
763 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
764
765 /*
766 * Signal the waiting EMT thread that everything went fine.
767 */
768 ASMAtomicXchgSize(&pThis->hwndDeviceChange, hwnd);
769 RTThreadUserSignal(ThreadSelf);
770 if (!hwnd)
771 {
772 LogFlow(("%s-%d: drvHostBaseMediaThread: returns VERR_GENERAL_FAILURE\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance));
773 return VERR_GENERAL_FAILURE;
774 }
775 LogFlow(("%s-%d: drvHostBaseMediaThread: Created hwndDeviceChange=%p\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, hwnd));
776
777 /*
778 * Message pump.
779 */
780 MSG Msg;
781 BOOL fRet;
782 while ((fRet = GetMessage(&Msg, NULL, 0, 0)) != FALSE)
783 {
784 if (fRet != -1)
785 {
786 TranslateMessage(&Msg);
787 DispatchMessage(&Msg);
788 }
789 //else: handle the error and possibly exit
790 }
791 Assert(!pThis->hwndDeviceChange);
792
793#else /* !__WIN__ */
794 bool fFirst = true;
795 int cRetries = 10;
796 while (!pThis->fShutdownPoller)
797 {
798 /*
799 * Perform the polling (unless we've run out of 50ms retries).
800 */
801 if ( pThis->pfnPoll
802 && cRetries-- > 0)
803 {
804
805 int rc = pThis->pfnPoll(pThis);
806 if (VBOX_FAILURE(rc))
807 {
808 RTSemEventWait(pThis->EventPoller, 50);
809 continue;
810 }
811 }
812
813 /*
814 * Signal EMT after the first go.
815 */
816 if (fFirst)
817 {
818 RTThreadUserSignal(ThreadSelf);
819 fFirst = false;
820 }
821
822 /*
823 * Sleep.
824 */
825 int rc = RTSemEventWait(pThis->EventPoller, pThis->cMilliesPoller);
826 if ( VBOX_FAILURE(rc)
827 && rc != VERR_TIMEOUT)
828 {
829 AssertMsgFailed(("rc=%Vrc\n", rc));
830 pThis->ThreadPoller = NIL_RTTHREAD;
831 LogFlow(("drvHostBaseMediaThread: returns %Vrc\n", rc));
832 return rc;
833 }
834 cRetries = 10;
835 }
836
837#endif /* !__WIN__ */
838
839 /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */
840 LogFlow(("%s-%d: drvHostBaseMediaThread: returns VINF_SUCCESS\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance));
841 return VINF_SUCCESS;
842}
843
844/* -=-=-=-=- driver interface -=-=-=-=- */
845
846
847/**
848 * Done state load operation.
849 *
850 * @returns VBox load code.
851 * @param pDrvIns Driver instance of the driver which registered the data unit.
852 * @param pSSM SSM operation handle.
853 */
854static DECLCALLBACK(int) drvHostBaseLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
855{
856 PDRVHOSTBASE pThis = PDMINS2DATA(pDrvIns, PDRVHOSTBASE);
857 LogFlow(("%s-%d: drvHostBaseMediaThread:\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance));
858 RTCritSectEnter(&pThis->CritSect);
859
860 /*
861 * Tell the device/driver above us that the media status is uncertain.
862 */
863 if (pThis->pDrvMountNotify)
864 {
865 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
866 if (pThis->fMediaPresent)
867 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
868 }
869
870 RTCritSectLeave(&pThis->CritSect);
871 return VINF_SUCCESS;
872}
873
874
875/** @copydoc FNPDMDRVDESTRUCT */
876DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns)
877{
878 PDRVHOSTBASE pThis = PDMINS2DATA(pDrvIns, PDRVHOSTBASE);
879 LogFlow(("%s-%d: drvHostBaseDestruct: iInstance=%d\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pDrvIns->iInstance));
880
881 /*
882 * Terminate the thread.
883 */
884 if (pThis->ThreadPoller != NIL_RTTHREAD)
885 {
886 pThis->fShutdownPoller = true;
887 int rc;
888 int cTimes = 50;
889 do
890 {
891#ifdef __WIN__
892 if (pThis->hwndDeviceChange)
893 PostMessage(pThis->hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
894#else
895 RTSemEventSignal(pThis->EventPoller);
896#endif
897 rc = RTThreadWait(pThis->ThreadPoller, 100, NULL);
898 } while (cTimes-- > 0 && rc == VERR_TIMEOUT);
899
900 if (!rc)
901 pThis->ThreadPoller = NIL_RTTHREAD;
902 }
903
904 /*
905 * Unlock the drive if we've locked it.
906 */
907 if ( pThis->fLocked
908 && pThis->FileDevice != NIL_RTFILE
909 && pThis->pfnDoLock)
910 {
911 int rc = pThis->pfnDoLock(pThis, false);
912 if (VBOX_SUCCESS(rc))
913 pThis->fLocked = false;
914 }
915
916 /*
917 * Cleanup the other resources.
918 */
919#ifdef __WIN__
920 if (pThis->hwndDeviceChange)
921 {
922 if (SetWindowLongPtr(pThis->hwndDeviceChange, GWLP_USERDATA, 0) == (LONG_PTR)pThis)
923 PostMessage(pThis->hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
924 pThis->hwndDeviceChange = NULL;
925 }
926#else
927 if (pThis->EventPoller != NULL)
928 {
929 RTSemEventDestroy(pThis->EventPoller);
930 pThis->EventPoller = NULL;
931 }
932#endif
933
934 if (pThis->FileDevice != NIL_RTFILE)
935 {
936 int rc = RTFileClose(pThis->FileDevice);
937 AssertRC(rc);
938 pThis->FileDevice = NIL_RTFILE;
939 }
940
941 if (pThis->pszDevice)
942 {
943 MMR3HeapFree(pThis->pszDevice);
944 pThis->pszDevice = NULL;
945 }
946
947 if (pThis->pszDeviceOpen)
948 {
949 RTStrFree(pThis->pszDeviceOpen);
950 pThis->pszDeviceOpen = NULL;
951 }
952
953 if (RTCritSectIsInitialized(&pThis->CritSect))
954 RTCritSectDelete(&pThis->CritSect);
955}
956
957
958/**
959 * Initializes the instance data (init part 1).
960 *
961 * The driver which derives from this base driver will override function pointers after
962 * calling this method, and complete the construction by calling DRVHostBaseInitFinish().
963 *
964 * On failure call DRVHostBaseDestruct().
965 *
966 * @returns VBox status code.
967 * @param pDrvIns Driver instance.
968 * @param pCfgHandle Configuration handle.
969 * @param enmType Device type.
970 */
971int DRVHostBaseInitData(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, PDMBLOCKTYPE enmType)
972{
973 PDRVHOSTBASE pThis = PDMINS2DATA(pDrvIns, PDRVHOSTBASE);
974 LogFlow(("%s-%d: DRVHostBaseInitData: iInstance=%d\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pDrvIns->iInstance));
975
976 /*
977 * Initialize most of the data members.
978 */
979 pThis->pDrvIns = pDrvIns;
980 pThis->ThreadPoller = NIL_RTTHREAD;
981 pThis->FileDevice = NIL_RTFILE;
982 pThis->enmType = enmType;
983
984 pThis->pfnGetMediaSize = drvHostBaseGetMediaSize;
985
986 /* IBase. */
987 pDrvIns->IBase.pfnQueryInterface = drvHostBaseQueryInterface;
988
989 /* IBlock. */
990 pThis->IBlock.pfnRead = drvHostBaseRead;
991 pThis->IBlock.pfnWrite = drvHostBaseWrite;
992 pThis->IBlock.pfnFlush = drvHostBaseFlush;
993 pThis->IBlock.pfnIsReadOnly = drvHostBaseIsReadOnly;
994 pThis->IBlock.pfnGetSize = drvHostBaseGetSize;
995 pThis->IBlock.pfnGetType = drvHostBaseGetType;
996 pThis->IBlock.pfnGetUuid = drvHostBaseGetUuid;
997
998 /* IBlockBios. */
999 pThis->IBlockBios.pfnGetGeometry = drvHostBaseGetGeometry;
1000 pThis->IBlockBios.pfnSetGeometry = drvHostBaseSetGeometry;
1001 pThis->IBlockBios.pfnGetTranslation = drvHostBaseGetTranslation;
1002 pThis->IBlockBios.pfnSetTranslation = drvHostBaseSetTranslation;
1003 pThis->IBlockBios.pfnIsVisible = drvHostBaseIsVisible;
1004 pThis->IBlockBios.pfnGetType = drvHostBaseBiosGetType;
1005
1006 /* IMount. */
1007 pThis->IMount.pfnMount = drvHostBaseMount;
1008 pThis->IMount.pfnUnmount = drvHostBaseUnmount;
1009 pThis->IMount.pfnIsMounted = drvHostBaseIsMounted;
1010 pThis->IMount.pfnLock = drvHostBaseLock;
1011 pThis->IMount.pfnUnlock = drvHostBaseUnlock;
1012 pThis->IMount.pfnIsLocked = drvHostBaseIsLocked;
1013
1014 /*
1015 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
1016 */
1017 pThis->pDrvBlockPort = (PPDMIBLOCKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_BLOCK_PORT);
1018 if (!pThis->pDrvBlockPort)
1019 {
1020 AssertMsgFailed(("Configuration error: No block port interface above!\n"));
1021 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1022 }
1023 pThis->pDrvMountNotify = (PPDMIMOUNTNOTIFY)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MOUNT_NOTIFY);
1024
1025 /*
1026 * Query configuration.
1027 */
1028 /* Device */
1029 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "Path", &pThis->pszDevice);
1030 if (VBOX_FAILURE(rc))
1031 {
1032 AssertMsgFailed(("Configuration error: query for \"Path\" string returned %Vra.\n", rc));
1033 return rc;
1034 }
1035
1036 /* Mountable */
1037 uint32_t u32;
1038 rc = CFGMR3QueryU32(pCfgHandle, "Interval", &u32);
1039 if (VBOX_SUCCESS(rc))
1040 pThis->cMilliesPoller = u32;
1041 else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1042 pThis->cMilliesPoller = 1000;
1043 else if (VBOX_FAILURE(rc))
1044 {
1045 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Vrc.\n", rc));
1046 return rc;
1047 }
1048
1049 /* ReadOnly */
1050 rc = CFGMR3QueryBool(pCfgHandle, "ReadOnly", &pThis->fReadOnlyConfig);
1051 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1052 pThis->fReadOnlyConfig = enmType == PDMBLOCKTYPE_DVD || enmType == PDMBLOCKTYPE_CDROM ? true : false;
1053 else if (VBOX_FAILURE(rc))
1054 {
1055 AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Vrc.\n", rc));
1056 return rc;
1057 }
1058
1059 /* Locked */
1060 rc = CFGMR3QueryBool(pCfgHandle, "Locked", &pThis->fLocked);
1061 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1062 pThis->fLocked = false;
1063 else if (VBOX_FAILURE(rc))
1064 {
1065 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Vrc.\n", rc));
1066 return rc;
1067 }
1068
1069 /* BIOS visible */
1070 rc = CFGMR3QueryBool(pCfgHandle, "BIOSVisible", &pThis->fBiosVisible);
1071 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1072 pThis->fBiosVisible = true;
1073 else if (VBOX_FAILURE(rc))
1074 {
1075 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Vrc.\n", rc));
1076 return rc;
1077 }
1078
1079 /* Uuid */
1080 char *psz;
1081 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Uuid", &psz);
1082 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1083 RTUuidClear(&pThis->Uuid);
1084 else if (VBOX_SUCCESS(rc))
1085 {
1086 rc = RTUuidFromStr(&pThis->Uuid, psz);
1087 if (VBOX_FAILURE(rc))
1088 {
1089 AssertMsgFailed(("Configuration error: Uuid from string failed on \"%s\", rc=%Vrc.\n", psz, rc));
1090 MMR3HeapFree(psz);
1091 return rc;
1092 }
1093 MMR3HeapFree(psz);
1094 }
1095 else
1096 {
1097 AssertMsgFailed(("Configuration error: Failed to obtain the uuid, rc=%Vrc.\n", rc));
1098 return rc;
1099 }
1100
1101 /* name to open & watch for */
1102#ifdef __WIN__
1103 int iBit = toupper(pThis->pszDevice[0]) - 'A';
1104 if ( iBit > 'Z' - 'A'
1105 || pThis->pszDevice[1] != ':'
1106 || pThis->pszDevice[2])
1107 {
1108 AssertMsgFailed(("Configuration error: Invalid drive specification: '%s'\n", pThis->pszDevice));
1109 return VERR_INVALID_PARAMETER;
1110 }
1111 pThis->fUnitMask = 1 << iBit;
1112 RTStrAPrintf(&pThis->pszDeviceOpen, "\\\\.\\%s", pThis->pszDevice);
1113#else
1114 pThis->pszDeviceOpen = RTStrDup(pThis->pszDevice);
1115#endif
1116 if (!pThis->pszDeviceOpen)
1117 return VERR_NO_MEMORY;
1118
1119 return VINF_SUCCESS;
1120}
1121
1122
1123/**
1124 * Do the 2nd part of the init after the derived driver has overridden the defaults.
1125 *
1126 * On failure call DRVHostBaseDestruct().
1127 *
1128 * @returns VBox status code.
1129 * @param pThis Pointer to the instance data.
1130 */
1131int DRVHostBaseInitFinish(PDRVHOSTBASE pThis)
1132{
1133 PPDMDRVINS pDrvIns = pThis->pDrvIns;
1134
1135 /* log config summary */
1136 Log(("%s-%d: pszDevice='%s' (%s) cMilliesPoller=%d fReadOnlyConfig=%d fLocked=%d fBIOSVisible=%d Uuid=%Vuuid\n",
1137 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pThis->pszDevice, pThis->pszDeviceOpen, pThis->cMilliesPoller,
1138 pThis->fReadOnlyConfig, pThis->fLocked, pThis->fBiosVisible, &pThis->Uuid));
1139
1140 /*
1141 * Check that there are no drivers below us.
1142 */
1143 PPDMIBASE pBase;
1144 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase);
1145 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
1146 {
1147 AssertMsgFailed(("Configuration error: No attached driver, please! (rc=%Vrc)\n", rc));
1148 return VERR_PDM_DRVINS_NO_ATTACH;
1149 }
1150
1151 /*
1152 * Register saved state.
1153 */
1154 rc = pDrvIns->pDrvHlp->pfnSSMRegister(pDrvIns, pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, 1, 0,
1155 NULL, NULL, NULL,
1156 NULL, NULL, drvHostBaseLoadDone);
1157 if (VBOX_FAILURE(rc))
1158 return rc;
1159
1160 /*
1161 * Verify type.
1162 */
1163#ifdef __WIN__
1164 UINT uDriveType = GetDriveType(pThis->pszDevice);
1165 switch (pThis->enmType)
1166 {
1167 case PDMBLOCKTYPE_FLOPPY_360:
1168 case PDMBLOCKTYPE_FLOPPY_720:
1169 case PDMBLOCKTYPE_FLOPPY_1_20:
1170 case PDMBLOCKTYPE_FLOPPY_1_44:
1171 case PDMBLOCKTYPE_FLOPPY_2_88:
1172 if (uDriveType != DRIVE_REMOVABLE)
1173 {
1174 AssertMsgFailed(("Configuration error: '%s' is not a floppy (type=%d)\n",
1175 pThis->pszDevice, uDriveType));
1176 return VERR_INVALID_PARAMETER;
1177 }
1178 break;
1179 case PDMBLOCKTYPE_CDROM:
1180 case PDMBLOCKTYPE_DVD:
1181 if (uDriveType != DRIVE_CDROM)
1182 {
1183 AssertMsgFailed(("Configuration error: '%s' is not a cdrom (type=%d)\n",
1184 pThis->pszDevice, uDriveType));
1185 return VERR_INVALID_PARAMETER;
1186 }
1187 break;
1188 case PDMBLOCKTYPE_HARD_DISK:
1189 default:
1190 AssertMsgFailed(("enmType=%d\n", pThis->enmType));
1191 return VERR_INVALID_PARAMETER;
1192 }
1193#endif
1194
1195 /*
1196 * Open the device.
1197 */
1198 rc = drvHostBaseReopen(pThis);
1199 if (VBOX_FAILURE(rc))
1200 {
1201 AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pThis->pszDevice, rc));
1202 pThis->FileDevice = NIL_RTFILE;
1203 return rc;
1204 }
1205#ifdef __WIN__
1206 DRVHostBaseMediaPresent(pThis);
1207#endif
1208
1209 /*
1210 * Lock the drive if that's required by the configuration.
1211 */
1212 if (pThis->fLocked)
1213 {
1214 if (pThis->pfnDoLock)
1215 rc = pThis->pfnDoLock(pThis, true);
1216 if (VBOX_FAILURE(rc))
1217 {
1218 AssertMsgFailed(("Failed to lock the dvd drive. rc=%Vrc\n", rc));
1219 return rc;
1220 }
1221 }
1222
1223#ifndef __WIN__
1224 /*
1225 * Create the event semaphore which the poller thread will wait on.
1226 */
1227 rc = RTSemEventCreate(&pThis->EventPoller);
1228 if (VBOX_FAILURE(rc))
1229 return rc;
1230#endif
1231
1232 /*
1233 * Initialize the critical section used for serializing the access to the media.
1234 */
1235 rc = RTCritSectInit(&pThis->CritSect);
1236 if (VBOX_FAILURE(rc))
1237 return rc;
1238
1239 /*
1240 * Start the thread which will poll for the media.
1241 */
1242 rc = RTThreadCreate(&pThis->ThreadPoller, drvHostBaseMediaThread, pThis, 0,
1243 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
1244 if (VBOX_FAILURE(rc))
1245 {
1246 AssertMsgFailed(("Failed to create poller thread. rc=%Vrc\n", rc));
1247 return rc;
1248 }
1249
1250 /*
1251 * Wait for the thread to start up (!w32:) and do one detection loop.
1252 */
1253 rc = RTThreadUserWait(pThis->ThreadPoller, 10000);
1254 AssertRC(rc);
1255#ifdef __WIN__
1256 if (!pThis->hwndDeviceChange)
1257 return VERR_GENERAL_FAILURE;
1258#endif
1259
1260 return rc;
1261}
1262
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