VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp@ 86714

Last change on this file since 86714 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.9 KB
Line 
1/* $Id: DrvHostDVD.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * DrvHostDVD - Host DVD block driver.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_HOST_DVD
23#include <iprt/asm.h>
24#include <VBox/vmm/pdmdrv.h>
25#include <VBox/vmm/pdmstorageifs.h>
26#include <iprt/asm.h>
27#include <iprt/assert.h>
28#include <iprt/file.h>
29#include <iprt/string.h>
30#include <iprt/thread.h>
31#include <iprt/critsect.h>
32#include <VBox/scsi.h>
33#include <VBox/scsiinline.h>
34
35#include "VBoxDD.h"
36#include "DrvHostBase.h"
37#include "ATAPIPassthrough.h"
38
39/** ATAPI sense info size. */
40#define ATAPI_SENSE_SIZE 64
41/** Size of an ATAPI packet. */
42#define ATAPI_PACKET_SIZE 12
43
44/**
45 * Host DVD driver instance data.
46 */
47typedef struct DRVHOSTDVD
48{
49 /** Base drivr data. */
50 DRVHOSTBASE Core;
51 /** The current tracklist of the loaded medium if passthrough is used. */
52 PTRACKLIST pTrackList;
53 /** ATAPI sense data. */
54 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
55 /** Flag whether to overwrite the inquiry data with our emulated settings. */
56 bool fInquiryOverwrite;
57} DRVHOSTDVD;
58/** Pointer to the host DVD driver instance data. */
59typedef DRVHOSTDVD *PDRVHOSTDVD;
60
61
62/*********************************************************************************************************************************
63* Internal Functions *
64*********************************************************************************************************************************/
65
66
67static uint8_t drvHostDvdCmdOK(PDRVHOSTDVD pThis)
68{
69 memset(pThis->abATAPISense, '\0', sizeof(pThis->abATAPISense));
70 pThis->abATAPISense[0] = 0x70;
71 pThis->abATAPISense[7] = 10;
72 return SCSI_STATUS_OK;
73}
74
75static uint8_t drvHostDvdCmdError(PDRVHOSTDVD pThis, const uint8_t *pabATAPISense, size_t cbATAPISense)
76{
77 Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
78 pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
79 memset(pThis->abATAPISense, '\0', sizeof(pThis->abATAPISense));
80 memcpy(pThis->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pThis->abATAPISense)));
81 return SCSI_STATUS_CHECK_CONDITION;
82}
83
84/** @todo deprecated function - doesn't provide enough info. Replace by direct
85 * calls to drvHostDvdCmdError() with full data. */
86static uint8_t drvHostDvdCmdErrorSimple(PDRVHOSTDVD pThis, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
87{
88 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
89 memset(abATAPISense, '\0', sizeof(abATAPISense));
90 abATAPISense[0] = 0x70 | (1 << 7);
91 abATAPISense[2] = uATAPISenseKey & 0x0f;
92 abATAPISense[7] = 10;
93 abATAPISense[12] = uATAPIASC;
94 return drvHostDvdCmdError(pThis, abATAPISense, sizeof(abATAPISense));
95}
96
97
98/**
99 * Parse the CDB and check whether it can be passed through safely.
100 *
101 * @returns Flag whether to passthrough to the device is considered safe.
102 * @param pThis The host DVD driver instance.
103 * @param pReq The request.
104 * @param pbCdb The CDB to parse.
105 * @param cbCdb Size of the CDB in bytes.
106 * @param cbBuf Size of the guest buffer.
107 * @param penmTxDir Where to store the transfer direction (guest to host or vice versa).
108 * @param pcbXfer Where to store the transfer size encoded in the CDB.
109 * @param pcbSector Where to store the sector size used for the transfer.
110 * @param pu8ScsiSts Where to store the SCSI status code.
111 */
112static bool drvHostDvdParseCdb(PDRVHOSTDVD pThis, PDRVHOSTBASEREQ pReq,
113 const uint8_t *pbCdb, size_t cbCdb, size_t cbBuf,
114 PDMMEDIATXDIR *penmTxDir, size_t *pcbXfer,
115 size_t *pcbSector, uint8_t *pu8ScsiSts)
116{
117 bool fPassthrough = false;
118
119 if ( pbCdb[0] == SCSI_REQUEST_SENSE
120 && (pThis->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
121 {
122 /* Handle the command here and copy sense data over. */
123 void *pvBuf = NULL;
124 int rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbBuf, false /*fWrite*/, &pvBuf);
125 if (RT_SUCCESS(rc))
126 {
127 memcpy(pvBuf, &pThis->abATAPISense[0], RT_MIN(sizeof(pThis->abATAPISense), cbBuf));
128 rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, false /* fWrite */, pvBuf);
129 AssertRC(rc);
130 drvHostDvdCmdOK(pThis);
131 *pu8ScsiSts = SCSI_STATUS_OK;
132 }
133 }
134 else
135 fPassthrough = ATAPIPassthroughParseCdb(pbCdb, cbCdb, cbBuf, pThis->pTrackList,
136 &pThis->abATAPISense[0], sizeof(pThis->abATAPISense),
137 penmTxDir, pcbXfer, pcbSector, pu8ScsiSts);
138
139 return fPassthrough;
140}
141
142
143/**
144 * Locks or unlocks the drive.
145 *
146 * @returns VBox status code.
147 * @param pThis The instance data.
148 * @param fLock True if the request is to lock the drive, false if to unlock.
149 */
150static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock)
151{
152 int rc = drvHostBaseDoLockOs(pThis, fLock);
153
154 LogFlow(("drvHostDvdDoLock(, fLock=%RTbool): returns %Rrc\n", fLock, rc));
155 return rc;
156}
157
158
159/** @interface_method_impl{PDMIMEDIA,pfnSendCmd} */
160static DECLCALLBACK(int) drvHostDvdSendCmd(PPDMIMEDIA pInterface, const uint8_t *pbCdb, size_t cbCdb,
161 PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf,
162 uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)
163{
164 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
165 int rc;
166 LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCdb[0], enmTxDir, *pcbBuf, cTimeoutMillies));
167
168 RTCritSectEnter(&pThis->CritSect);
169 /* Pass the request on to the internal scsi command interface. */
170 if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE)
171 memset(pvBuf, '\0', *pcbBuf); /* we got read size, but zero it anyway. */
172 rc = drvHostBaseScsiCmdOs(pThis, pbCdb, cbCdb, enmTxDir, pvBuf, pcbBuf, pabSense, cbSense, cTimeoutMillies);
173 if (rc == VERR_UNRESOLVED_ERROR)
174 /* sense information set */
175 rc = VERR_DEV_IO_ERROR;
176
177 if (pbCdb[0] == SCSI_GET_EVENT_STATUS_NOTIFICATION)
178 {
179 uint8_t *pbBuf = (uint8_t*)pvBuf;
180 Log2(("Event Status Notification class=%#02x supported classes=%#02x\n", pbBuf[2], pbBuf[3]));
181 if (RT_BE2H_U16(*(uint16_t*)pbBuf) >= 6)
182 Log2((" event %#02x %#02x %#02x %#02x\n", pbBuf[4], pbBuf[5], pbBuf[6], pbBuf[7]));
183 }
184 RTCritSectLeave(&pThis->CritSect);
185
186 LogFlow(("%s: rc=%Rrc\n", __FUNCTION__, rc));
187 return rc;
188}
189
190
191/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSendScsiCmd} */
192static DECLCALLBACK(int) drvHostDvdIoReqSendScsiCmd(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
193 uint32_t uLun, const uint8_t *pbCdb, size_t cbCdb,
194 PDMMEDIAEXIOREQSCSITXDIR enmTxDir, PDMMEDIAEXIOREQSCSITXDIR *penmTxDirRet,
195 size_t cbBuf, uint8_t *pabSense, size_t cbSense, size_t *pcbSenseRet,
196 uint8_t *pu8ScsiSts, uint32_t cTimeoutMillies)
197{
198 RT_NOREF3(uLun, cTimeoutMillies, enmTxDir);
199
200 PDRVHOSTDVD pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDVD, Core.IMediaEx);
201 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
202 int rc = VINF_SUCCESS;
203
204 LogFlow(("%s: pbCdb[0]=%#04x{%s} enmTxDir=%d cbBuf=%zu timeout=%u\n",
205 __FUNCTION__, pbCdb[0], SCSICmdText(pbCdb[0]), enmTxDir, cbBuf, cTimeoutMillies));
206
207 RTCritSectEnter(&pThis->Core.CritSect);
208
209 /*
210 * Parse the command first to fend off any illegal or dangerous commands we don't want the guest
211 * to execute on the host drive.
212 */
213 PDMMEDIATXDIR enmXferDir = PDMMEDIATXDIR_NONE;
214 size_t cbXfer = 0;
215 size_t cbSector = 0;
216 size_t cbScsiCmdBufLimit = drvHostBaseScsiCmdGetBufLimitOs(&pThis->Core);
217 bool fPassthrough = drvHostDvdParseCdb(pThis, pReq, pbCdb, cbCdb, cbBuf,
218 &enmXferDir, &cbXfer, &cbSector, pu8ScsiSts);
219 if (fPassthrough)
220 {
221 void *pvBuf = NULL;
222 size_t cbXferCur = cbXfer;
223
224 pReq->cbReq = cbXfer;
225 pReq->cbResidual = cbXfer;
226
227 if (cbXfer)
228 rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbXfer, enmXferDir == PDMMEDIATXDIR_TO_DEVICE, &pvBuf);
229
230 if (cbXfer > cbScsiCmdBufLimit)
231 {
232 /* Linux accepts commands with up to 100KB of data, but expects
233 * us to handle commands with up to 128KB of data. The usual
234 * imbalance of powers. */
235 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
236 uint32_t iATAPILBA, cSectors;
237 uint8_t *pbBuf = (uint8_t *)pvBuf;
238
239 switch (pbCdb[0])
240 {
241 case SCSI_READ_10:
242 case SCSI_WRITE_10:
243 case SCSI_WRITE_AND_VERIFY_10:
244 iATAPILBA = scsiBE2H_U32(pbCdb + 2);
245 cSectors = scsiBE2H_U16(pbCdb + 7);
246 break;
247 case SCSI_READ_12:
248 case SCSI_WRITE_12:
249 iATAPILBA = scsiBE2H_U32(pbCdb + 2);
250 cSectors = scsiBE2H_U32(pbCdb + 6);
251 break;
252 case SCSI_READ_CD:
253 iATAPILBA = scsiBE2H_U32(pbCdb + 2);
254 cSectors = scsiBE2H_U24(pbCdb + 6);
255 break;
256 case SCSI_READ_CD_MSF:
257 iATAPILBA = scsiMSF2LBA(pbCdb + 3);
258 cSectors = scsiMSF2LBA(pbCdb + 6) - iATAPILBA;
259 break;
260 default:
261 AssertMsgFailed(("Don't know how to split command %#04x\n", pbCdb[0]));
262 LogRelMax(10, ("HostDVD#%u: CD-ROM passthrough split error\n", pThis->Core.pDrvIns->iInstance));
263 *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
264 rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, enmXferDir == PDMMEDIATXDIR_TO_DEVICE, pvBuf);
265 RTCritSectLeave(&pThis->Core.CritSect);
266 return VINF_SUCCESS;
267 }
268 memcpy(aATAPICmd, pbCdb, RT_MIN(cbCdb, ATAPI_PACKET_SIZE));
269 uint32_t cReqSectors = 0;
270 for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
271 {
272 if (i * cbSector > cbScsiCmdBufLimit)
273 cReqSectors = (uint32_t)(cbScsiCmdBufLimit / cbSector);
274 else
275 cReqSectors = i;
276 uint32_t cbCurrTX = (uint32_t)cbSector * cReqSectors;
277 switch (pbCdb[0])
278 {
279 case SCSI_READ_10:
280 case SCSI_WRITE_10:
281 case SCSI_WRITE_AND_VERIFY_10:
282 scsiH2BE_U32(aATAPICmd + 2, iATAPILBA);
283 scsiH2BE_U16(aATAPICmd + 7, cReqSectors);
284 break;
285 case SCSI_READ_12:
286 case SCSI_WRITE_12:
287 scsiH2BE_U32(aATAPICmd + 2, iATAPILBA);
288 scsiH2BE_U32(aATAPICmd + 6, cReqSectors);
289 break;
290 case SCSI_READ_CD:
291 scsiH2BE_U32(aATAPICmd + 2, iATAPILBA);
292 scsiH2BE_U24(aATAPICmd + 6, cReqSectors);
293 break;
294 case SCSI_READ_CD_MSF:
295 scsiLBA2MSF(aATAPICmd + 3, iATAPILBA);
296 scsiLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
297 break;
298 }
299 rc = drvHostBaseScsiCmdOs(&pThis->Core, aATAPICmd, sizeof(aATAPICmd),
300 enmXferDir, pbBuf, &cbCurrTX,
301 &pThis->abATAPISense[0], sizeof(pThis->abATAPISense),
302 cTimeoutMillies /**< @todo timeout */);
303 if (rc != VINF_SUCCESS)
304 break;
305
306 pReq->cbResidual -= cbCurrTX;
307 iATAPILBA += cReqSectors;
308 pbBuf += cbSector * cReqSectors;
309 }
310 }
311 else
312 {
313 uint32_t cbXferTmp = (uint32_t)cbXferCur;
314 rc = drvHostBaseScsiCmdOs(&pThis->Core, pbCdb, cbCdb, enmXferDir, pvBuf, &cbXferTmp,
315 &pThis->abATAPISense[0], sizeof(pThis->abATAPISense), cTimeoutMillies);
316 if (RT_SUCCESS(rc))
317 pReq->cbResidual -= cbXferTmp;
318 }
319
320 if (RT_SUCCESS(rc))
321 {
322 /* Do post processing for certain commands. */
323 switch (pbCdb[0])
324 {
325 case SCSI_SEND_CUE_SHEET:
326 case SCSI_READ_TOC_PMA_ATIP:
327 {
328 if (!pThis->pTrackList)
329 rc = ATAPIPassthroughTrackListCreateEmpty(&pThis->pTrackList);
330
331 if (RT_SUCCESS(rc))
332 rc = ATAPIPassthroughTrackListUpdate(pThis->pTrackList, pbCdb, pvBuf, cbXfer);
333
334 if (RT_FAILURE(rc))
335 LogRelMax(10, ("HostDVD#%u: Error (%Rrc) while updating the tracklist during %s, burning the disc might fail\n",
336 pThis->Core.pDrvIns->iInstance, rc,
337 pbCdb[0] == SCSI_SEND_CUE_SHEET ? "SEND CUE SHEET" : "READ TOC/PMA/ATIP"));
338 break;
339 }
340 case SCSI_SYNCHRONIZE_CACHE:
341 {
342 if (pThis->pTrackList)
343 ATAPIPassthroughTrackListClear(pThis->pTrackList);
344 break;
345 }
346 }
347
348 if (enmXferDir == PDMMEDIATXDIR_FROM_DEVICE)
349 {
350 Assert(cbXferCur <= cbXfer);
351
352 if ( pbCdb[0] == SCSI_INQUIRY
353 && pThis->fInquiryOverwrite)
354 {
355 const char *pszInqVendorId = "VBOX";
356 const char *pszInqProductId = "CD-ROM";
357 const char *pszInqRevision = "1.0";
358
359 if (pThis->Core.pDrvMediaPort->pfnQueryScsiInqStrings)
360 {
361 rc = pThis->Core.pDrvMediaPort->pfnQueryScsiInqStrings(pThis->Core.pDrvMediaPort, &pszInqVendorId,
362 &pszInqProductId, &pszInqRevision);
363 AssertRC(rc);
364 }
365 /* Make sure that the real drive cannot be identified.
366 * Motivation: changing the VM configuration should be as
367 * invisible as possible to the guest. */
368 if (cbXferCur >= 8 + 8)
369 scsiPadStr((uint8_t *)pvBuf + 8, pszInqVendorId, 8);
370 if (cbXferCur >= 16 + 16)
371 scsiPadStr((uint8_t *)pvBuf + 16, pszInqProductId, 16);
372 if (cbXferCur >= 32 + 4)
373 scsiPadStr((uint8_t *)pvBuf + 32, pszInqRevision, 4);
374 }
375
376 if (cbXferCur)
377 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbXferCur, cbXferCur, (uint8_t *)pvBuf));
378 }
379
380 *pu8ScsiSts = drvHostDvdCmdOK(pThis);
381 }
382 else
383 {
384 do
385 {
386 /* don't log superfluous errors */
387 if ( rc == VERR_DEV_IO_ERROR
388 && ( pbCdb[0] == SCSI_TEST_UNIT_READY
389 || pbCdb[0] == SCSI_READ_CAPACITY
390 || pbCdb[0] == SCSI_READ_DVD_STRUCTURE
391 || pbCdb[0] == SCSI_READ_TOC_PMA_ATIP))
392 break;
393 LogRelMax(10, ("HostDVD#%u: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
394 pThis->Core.pDrvIns->iInstance, pbCdb[0], pThis->abATAPISense[2] & 0x0f,
395 pThis->abATAPISense[12], pThis->abATAPISense[13], rc));
396 } while (0);
397 *pu8ScsiSts = SCSI_STATUS_CHECK_CONDITION;
398 rc = VINF_SUCCESS;
399 }
400
401 if (cbXfer)
402 rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbXfer, enmXferDir == PDMMEDIATXDIR_TO_DEVICE, pvBuf);
403 }
404
405 /*
406 * We handled the command, check the status code and copy over the sense data if
407 * it is CHECK CONDITION.
408 */
409 if ( *pu8ScsiSts == SCSI_STATUS_CHECK_CONDITION
410 && VALID_PTR(pabSense)
411 && cbSense > 0)
412 {
413 size_t cbSenseCpy = RT_MIN(cbSense, sizeof(pThis->abATAPISense));
414
415 memcpy(pabSense, &pThis->abATAPISense[0], cbSenseCpy);
416 if (pcbSenseRet)
417 *pcbSenseRet = cbSenseCpy;
418 }
419
420 if (penmTxDirRet)
421 {
422 switch (enmXferDir)
423 {
424 case PDMMEDIATXDIR_NONE:
425 *penmTxDirRet = PDMMEDIAEXIOREQSCSITXDIR_NONE;
426 break;
427 case PDMMEDIATXDIR_FROM_DEVICE:
428 *penmTxDirRet = PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
429 break;
430 case PDMMEDIATXDIR_TO_DEVICE:
431 *penmTxDirRet = PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE;
432 break;
433 default:
434 *penmTxDirRet = PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN;
435 }
436 }
437
438 RTCritSectLeave(&pThis->Core.CritSect);
439
440 LogFlow(("%s: rc=%Rrc\n", __FUNCTION__, rc));
441 return rc;
442}
443
444
445/* -=-=-=-=- driver interface -=-=-=-=- */
446
447
448/** @interface_method_impl{PDMDRVREG,pfnDestruct} */
449static DECLCALLBACK(void) drvHostDvdDestruct(PPDMDRVINS pDrvIns)
450{
451 PDRVHOSTDVD pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDVD);
452
453 if (pThis->pTrackList)
454 {
455 ATAPIPassthroughTrackListDestroy(pThis->pTrackList);
456 pThis->pTrackList = NULL;
457 }
458
459 DRVHostBaseDestruct(pDrvIns);
460}
461
462/**
463 * Construct a host dvd drive driver instance.
464 *
465 * @copydoc FNPDMDRVCONSTRUCT
466 */
467static DECLCALLBACK(int) drvHostDvdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
468{
469 RT_NOREF(fFlags);
470 PDRVHOSTDVD pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDVD);
471 LogFlow(("drvHostDvdConstruct: iInstance=%d\n", pDrvIns->iInstance));
472
473 int rc = CFGMR3QueryBoolDef(pCfg, "InquiryOverwrite", &pThis->fInquiryOverwrite, true);
474 if (RT_FAILURE(rc))
475 return PDMDRV_SET_ERROR(pDrvIns, rc,
476 N_("HostDVD configuration error: failed to read \"InquiryOverwrite\" as boolean"));
477
478 bool fPassthrough;
479 rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough);
480 if (RT_SUCCESS(rc) && fPassthrough)
481 {
482 pThis->Core.IMedia.pfnSendCmd = drvHostDvdSendCmd;
483 pThis->Core.IMediaEx.pfnIoReqSendScsiCmd = drvHostDvdIoReqSendScsiCmd;
484 /* Passthrough requires opening the device in R/W mode. */
485 pThis->Core.fReadOnlyConfig = false;
486 }
487
488 pThis->Core.pfnDoLock = drvHostDvdDoLock;
489
490 /*
491 * Init instance data.
492 */
493 rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0InquiryOverwrite\0",
494 PDMMEDIATYPE_DVD);
495 LogFlow(("drvHostDvdConstruct: returns %Rrc\n", rc));
496 return rc;
497}
498
499
500/**
501 * Block driver registration record.
502 */
503const PDMDRVREG g_DrvHostDVD =
504{
505 /* u32Version */
506 PDM_DRVREG_VERSION,
507 /* szName */
508 "HostDVD",
509 /* szRCMod */
510 "",
511 /* szR0Mod */
512 "",
513 /* pszDescription */
514 "Host DVD Block Driver.",
515 /* fFlags */
516 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
517 /* fClass. */
518 PDM_DRVREG_CLASS_BLOCK,
519 /* cMaxInstances */
520 ~0U,
521 /* cbInstance */
522 sizeof(DRVHOSTDVD),
523 /* pfnConstruct */
524 drvHostDvdConstruct,
525 /* pfnDestruct */
526 drvHostDvdDestruct,
527 /* pfnRelocate */
528 NULL,
529 /* pfnIOCtl */
530 NULL,
531 /* pfnPowerOn */
532 NULL,
533 /* pfnReset */
534 NULL,
535 /* pfnSuspend */
536 NULL,
537 /* pfnResume */
538 NULL,
539 /* pfnAttach */
540 NULL,
541 /* pfnDetach */
542 NULL,
543 /* pfnPowerOff */
544 NULL,
545 /* pfnSoftReset */
546 NULL,
547 /* u32EndVersion */
548 PDM_DRVREG_VERSION
549};
550
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