VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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