VirtualBox

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

Last change on this file since 980 was 262, checked in by vboxsync, 18 years ago

Produce a better error message if the host CD/DVD drive is not accessible.

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