/* $Id$ */
/** @file
* VBox storage devices: ATAPI emulation (common code for DevATA and DevAHCI).
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "ATAPIPassthrough.h"
/** The track was not detected yet. */
/** The track is the lead in track of the medium. */
/** The track is the lead out track of the medium. */
/** Don't clear already detected tracks on the medium. */
/**
* Track main data form.
*/
typedef enum TRACKDATAFORM
{
/** Invalid data form. */
/** 2352 bytes of data. */
/** CDDA data is pause. */
/** Mode 1 with 2048 bytes sector size. */
/** Mode 1 with 2352 bytes sector size. */
/** Mode 1 with 0 bytes sector size (generated by the drive). */
/** XA Mode with 2336 bytes sector size. */
/** XA Mode with 2352 bytes sector size. */
/** XA Mode with 0 bytes sector size (generated by the drive). */
/** Mode 2 with 2336 bytes sector size. */
/** Mode 2 with 2352 bytes sector size. */
/** Mode 2 with 0 bytes sector size (generated by the drive). */
/**
* Subchannel data form.
*/
typedef enum SUBCHNDATAFORM
{
/** Invalid subchannel data form. */
/** 0 bytes for the subchannel (generated by the drive). */
/** 96 bytes of data for the subchannel. */
/**
* Track entry.
*/
typedef struct TRACK
{
/** Start LBA of the track. */
/** Number of sectors in the track. */
/** Data form of main data. */
/** Data form of sub channel. */
/** Flags for the track. */
/**
* Media track list.
*/
typedef struct TRACKLIST
{
/** Number of detected tracks of the current medium. */
unsigned cTracksCurrent;
/** Maximum number of tracks the list can contain. */
unsigned cTracksMax;
/** Variable list of tracks. */
{
}
{
}
{
}
{
}
/**
* Reallocate the given track list to be able to hold the given number of tracks.
*
* @returns VBox status code.
* @param pTrackList The track list to reallocate.
* @param cTracks Number of tracks the list must be able to hold.
* @param fFlags Flags for the reallocation.
*/
{
{
if (paTracksNew)
{
/* Mark new tracks as undetected. */
}
else
rc = VERR_NO_MEMORY;
}
return rc;
}
/**
* Initilizes the given track from the given CUE sheet entry.
*
* @returns nothing.
* @param pTrack The track to initialize.
* @param pbCueSheetEntry CUE sheet entry to use.
*/
static void atapiTrackListEntryCreateFromCueSheetEntry(PTRACK pTrack, const uint8_t *pbCueSheetEntry)
{
/* Determine size of main data based on the data form field. */
{
case 0x00: /* CD-DA with data. */
break;
case 0x01: /* CD-DA without data (used for pauses between tracks). */
break;
case 0x10: /* CD-ROM mode 1 */
case 0x12:
break;
case 0x11:
case 0x13:
break;
case 0x14:
break;
case 0x20: /* CD-ROM XA, CD-I */
case 0x22:
break;
case 0x21:
case 0x23:
break;
case 0x24:
break;
case 0x31: /* CD-ROM Mode 2 */
case 0x33:
break;
case 0x30:
case 0x32:
break;
case 0x34:
break;
default: /* Reserved, invalid mode. Log and leave default sector size. */
LogRel(("ATA: Invalid data form mode %d for current CUE sheet\n",
}
/* Determine size of sub channel data based on data form field. */
{
case 0x00: /* Sub channel all zeroes, autogenerated by the drive. */
break;
case 0x01:
case 0x03:
break;
default:
LogRel(("ATA: Invalid sub-channel data form mode %u for current CUE sheet\n",
}
{
/* Calculate number of sectors from the next entry. */
}
else
{
}
}
/**
* Update the track list from a SEND CUE SHEET request.
*
* @returns VBox status code.
* @param pTrackList Track list to update.
* @param pbCDB CDB of the SEND CUE SHEET request.
* @param pvBuf The CUE sheet.
*/
static int atapiTrackListUpdateFromSendCueSheet(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
if (RT_SUCCESS(rc))
{
for (unsigned i = 0; i < cTracks; i++)
{
if (i == 0)
pTrack++;
pbCueSheet += 8;
}
}
return rc;
}
static int atapiTrackListUpdateFromSendDvdStructure(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
return VERR_NOT_IMPLEMENTED;
}
/**
* Update track list from formatted TOC data.
*
* @returns VBox status code.
* @param pTrackList The track list to update.
* @param fMSF Flag whether block addresses are in MSF or LBA format.
* @param pbBuf Buffer holding the formatted TOC.
* @param cbBuffer Size of the buffer.
*/
{
unsigned cTracks;
cbToc -= 2;
pbBuf += 4;
if (RT_SUCCESS(rc))
{
for (unsigned i = iTrackFirst; i < cTracks; i++)
{
else
if (fMSF)
else
{
/* Calculate number of sectors from the next entry. */
if (fMSF)
else
}
else
pbBuf += 8;
pTrack++;
}
}
return rc;
}
static int atapiTrackListUpdateFromReadTocPmaAtip(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
switch (uFmt)
{
case 0x00:
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
break;
case 0x05:
break;
default:
}
return rc;
}
static int atapiTrackListUpdateFromReadTrackInformation(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
return VERR_NOT_IMPLEMENTED;
}
static int atapiTrackListUpdateFromReadDvdStructure(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
return VERR_NOT_IMPLEMENTED;
}
static int atapiTrackListUpdateFromReadDiscInformation(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
return VERR_NOT_IMPLEMENTED;
}
/**
* Converts the given track data form to a string.
*
* @returns Track data form as a string.
* @param enmTrackDataForm The track main data form.
*/
{
switch (enmTrackDataForm)
{
case TRACKDATAFORM_CDDA:
return "CD-DA";
case TRACKDATAFORM_CDDA_PAUSE:
return "CD-DA Pause";
case TRACKDATAFORM_MODE1_2048:
return "Mode 1 (2048 bytes)";
case TRACKDATAFORM_MODE1_2352:
return "Mode 1 (2352 bytes)";
case TRACKDATAFORM_MODE1_0:
return "Mode 1 (0 bytes)";
case TRACKDATAFORM_XA_2336:
return "XA (2336 bytes)";
case TRACKDATAFORM_XA_2352:
return "XA (2352 bytes)";
case TRACKDATAFORM_XA_0:
return "XA (0 bytes)";
case TRACKDATAFORM_MODE2_2336:
return "Mode 2 (2336 bytes)";
case TRACKDATAFORM_MODE2_2352:
return "Mode 2 (2352 bytes)";
case TRACKDATAFORM_MODE2_0:
return "Mode 2 (0 bytes)";
case TRACKDATAFORM_INVALID:
default:
return "Invalid";
}
}
/**
* Converts the given subchannel data form to a string.
*
* @returns Subchannel data form as a string.
* @param enmSubChnDataForm The subchannel main data form.
*/
{
switch (enmSubChnDataForm)
{
case SUBCHNDATAFORM_0:
return "0";
case SUBCHNDATAFORM_96:
return "96";
case SUBCHNDATAFORM_INVALID:
default:
return "Invalid";
}
}
/**
* Dump the complete track list to the release log.
*
* @returns nothing.
* @param pTrackList The track list to dump.
*/
{
for (unsigned i = 0; i < pTrackList->cTracksCurrent; i++)
{
LogRel((" Track %u: LBAStart=%lld cSectors=%u enmMainDataForm=%s enmSubChnDataForm=%s fFlags=[%s%s%s]\n",
i, pTrack->iLbaStart, pTrack->cSectors, atapiTrackListMainDataFormToString(pTrack->enmMainDataForm),
}
}
{
if (pTrackList)
{
rc = VINF_SUCCESS;
}
return rc;
}
{
if (pTrackList->paTracks)
}
{
pTrackList->cTracksCurrent = 0;
/* Mark all tracks as undetected. */
for (unsigned i = 0; i < pTrackList->cTracksMax; i++)
}
DECLHIDDEN(int) ATAPIPassthroughTrackListUpdate(PTRACKLIST pTrackList, const uint8_t *pbCDB, const void *pvBuf)
{
switch (pbCDB[0])
{
case SCSI_SEND_CUE_SHEET:
break;
case SCSI_SEND_DVD_STRUCTURE:
break;
case SCSI_READ_TOC_PMA_ATIP:
break;
break;
case SCSI_READ_DVD_STRUCTURE:
break;
break;
default:
}
#ifdef LOG_ENABLED
#endif
return rc;
}
DECLHIDDEN(uint32_t) ATAPIPassthroughTrackListGetSectorSizeFromLba(PTRACKLIST pTrackList, uint32_t iAtapiLba)
{
if (pTrackList->cTracksCurrent)
{
{
/* Lead-In area, this is always the first entry in the cue sheet. */
LogFlowFunc(("Selected Lead-In area\n"));
}
else
{
/* Go through the track list and find the correct entry. */
{
continue;
break;
pTrack++;
}
}
if (pTrack)
{
switch (pTrack->enmMainDataForm)
{
case TRACKDATAFORM_CDDA:
case TRACKDATAFORM_MODE1_2352:
case TRACKDATAFORM_XA_2352:
case TRACKDATAFORM_MODE2_2352:
cbAtapiSector = 2352;
break;
case TRACKDATAFORM_MODE1_2048:
cbAtapiSector = 2048;
break;
case TRACKDATAFORM_CDDA_PAUSE:
case TRACKDATAFORM_MODE1_0:
case TRACKDATAFORM_XA_0:
case TRACKDATAFORM_MODE2_0:
cbAtapiSector = 0;
break;
case TRACKDATAFORM_XA_2336:
case TRACKDATAFORM_MODE2_2336:
cbAtapiSector = 2336;
break;
case TRACKDATAFORM_INVALID:
default:
}
switch (pTrack->enmSubChnDataForm)
{
case SUBCHNDATAFORM_0:
break;
case SUBCHNDATAFORM_96:
cbAtapiSector += 96;
break;
case SUBCHNDATAFORM_INVALID:
default:
}
}
}
return cbAtapiSector;
}