📄 cdio.cpp
字号:
}
//---------------------------------------------------------------------------
//
// Function: AtapiLoadMedia
//
// synopsis: Process a IOCTL_CDROM_LOAD_MEDIA/IOCTL_CDROM_EJECT_MEDIA request
//
// ENTRY
// Nothing
// EXIT
// Extended error set on failure
//
//-----------------------------------------------------------------------------
DWORD CDisk::AtapiLoadMedia(BOOL bEject)
{
ATAPI_COMMAND_PACKET CmdPkt;
SGX_BUF SgBuf;
DWORD dwRet;
DWORD dwError = ERROR_SUCCESS;
DEBUGMSG(ZONE_IOCTL, (TEXT("ATAPI:ATAPILoadMedia - Entered. Load=%s\r\n"), bEject ? L"TRUE": L"FALSE"));
memset((void *)&CmdPkt, 0, sizeof(CmdPkt));
CmdPkt.Opcode = ATAPI_PACKET_CMD_START_STOP;
CmdPkt.Byte_4 = bEject ? 2 : 3;
SgBuf.sb_len = 0;
SgBuf.sb_buf = NULL;
if (AtapiSendCommand(&CmdPkt)) {
if (!AtapiReceiveData(&SgBuf, 0, &dwRet)) {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("ATAPI::LoadMedia failed on receive\r\n")));
dwError = ERROR_READ_FAULT;
}
if (!bEject) {
Sleep(5000);
AtapiIsUnitReadyEx();
}
} else {
return ERROR_GEN_FAILURE;
}
return dwError;
}
DWORD CDisk::AtapiStartDisc()
{
ATAPI_COMMAND_PACKET CmdPkt;
SGX_BUF SgBuf;
DWORD dwRet;
DWORD dwError = ERROR_SUCCESS;
DEBUGMSG(ZONE_CDROM, (TEXT("ATAPI:AtapiStartDisc - Entered.\r\n")));
memset((void *)&CmdPkt, 0, sizeof(CmdPkt));
CmdPkt.Opcode = ATAPI_PACKET_CMD_START_STOP;
CmdPkt.Byte_4 = 1;
SgBuf.sb_len = 0;
SgBuf.sb_buf = NULL;
if (AtapiSendCommand(&CmdPkt)) {
if (!AtapiReceiveData(&SgBuf, 1, &dwRet)) {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("ATAPI::LoadMedia failed on receive\r\n")));
dwError = ERROR_READ_FAULT;
}
} else {
return ERROR_GEN_FAILURE;
}
return dwError;
}
DWORD CDisk::AtapiReadQChannel(PIOREQ pIOReq)
{
ATAPI_COMMAND_PACKET CmdPkt;
SGX_BUF SgBuf;
DWORD dwRet;
DWORD dwError = ERROR_SUCCESS;
CDROM_SUB_Q_DATA_FORMAT *pcsqdf = (CDROM_SUB_Q_DATA_FORMAT *)pIOReq->pInBuf;
SUB_Q_CHANNEL_DATA sqcd;
DWORD dwDataSize = 0;
if (!pcsqdf || !pIOReq->pOutBuf || (sizeof(CDROM_SUB_Q_DATA_FORMAT) != pIOReq->dwInBufSize)) {
return ERROR_BAD_ARGUMENTS;
}
switch( pcsqdf->Format) {
case IOCTL_CDROM_CURRENT_POSITION:
dwDataSize = sizeof(SUB_Q_CURRENT_POSITION);
break;
case IOCTL_CDROM_MEDIA_CATALOG:
dwDataSize = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
break;
case IOCTL_CDROM_TRACK_ISRC:
dwDataSize = sizeof(SUB_Q_TRACK_ISRC);
break;
default:
dwError = ERROR_BAD_FORMAT;
}
if (pIOReq->dwOutBufSize < dwDataSize) {
dwError = ERROR_BAD_ARGUMENTS;
}
if (dwError == ERROR_SUCCESS) {
memset((void *)&CmdPkt, 0, sizeof(CmdPkt));
CmdPkt.Opcode = ATAPI_PACKET_CMD_READ_SUB_CHAN;
CmdPkt.Byte_1 = 0x00;
CmdPkt.Byte_2 = 0x40; // Header + data required
CmdPkt.Byte_3 = (BYTE)(pcsqdf->Format);
CmdPkt.Byte_8 = (BYTE)dwDataSize;
SgBuf.sb_len = dwDataSize;
SgBuf.sb_buf = (PBYTE) &sqcd;
if (AtapiSendCommand(&CmdPkt)) {
if (!AtapiReceiveData(&SgBuf, 1, &dwRet)) {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("ATAPI::ReadQChannel failed on receive\r\n")));
dwError = ERROR_READ_FAULT;
} else {
memcpy( pIOReq->pOutBuf, (LPBYTE)&sqcd, dwDataSize);
}
} else {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("ATAPI::ReadQChannel failed on SendCommand\r\n")));
dwError = ERROR_GEN_FAILURE;
}
}
return dwError;
}
//---------------------------------------------------------------------------
//
// Function: AtapiGetToc
//
// synopsis: Gets the table of contents from the media
//
// ENTRY
// Nothing
// EXIT
// Extended error set on failure
//
//-----------------------------------------------------------------------------
BOOL CDisk::AtapiGetToc(CDROM_TOC * pTOC)
{
ATAPI_COMMAND_PACKET CmdPkt;
SGX_BUF SgBuf;
DWORD dwRet;
BOOL fRet = TRUE;
memset((void *)&CmdPkt, 0, sizeof(CmdPkt));
CmdPkt.Opcode = ATAPI_PACKET_CMD_READ_TOC;
CmdPkt.Byte_1 = 0x02; // Use MSF Address Format
CmdPkt.Byte_7 = (BYTE)((sizeof(CDROM_TOC)>> 8) &0x0FF); //3
CmdPkt.Byte_8 = (BYTE)(sizeof(CDROM_TOC) &0x0FF); // 24
SgBuf.sb_len = sizeof(CDROM_TOC);
SgBuf.sb_buf = (PBYTE) pTOC;
if (AtapiSendCommand(&CmdPkt)) {
if (!AtapiReceiveData(&SgBuf, 1, &dwRet)) {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("ATAPI::GetToc failed on receive\r\n")));
fRet = FALSE;
} else {
WORD wTOCDataLen = (MAKEWORD(pTOC->Length[1], pTOC->Length[0]) - 2);
//
// Minus 4 for the the entire header
//
if (wTOCDataLen != (dwRet - 4))
{
DEBUGMSG(ZONE_ERROR, (TEXT("ATAPI:AtapiGetToc - Bad Length in TOC Header = %d, Expecting = %d\r\n"), wTOCDataLen, dwRet - 4));
fRet = FALSE;
}
if ((wTOCDataLen % sizeof(TRACK_DATA)) != 0)
{
DEBUGMSG( ZONE_ERROR, (TEXT("ATAPI:AtapiGetToc - Data length = %d which is not a multiple of CDREADTOC_MSFINFO size\r\n"), wTOCDataLen));
fRet = FALSE;
}
}
} else {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("ATAPI::GetToc failed on SendCommand\r\n")));
fRet = FALSE;
}
return fRet;
}
//---------------------------------------------------------------------------
//
// Function: AtapiGetDiscInfo
//
// Synopsis: implements CDROM_IOCTL_DISC_INFO - Get Disc Information
//
// This function returns the TOC (table of contents) information
// from the Q-channel in the lead-in track of the disc, which
// indicates the starting and ending tracks and the start of
// the lead-out track.
//
// The first and last track number are binary values, not BCD.
//
// It is recommended that the information from the TOC be read
// in and cached on drive initialization so that when this function
// is called, there is not need to interrupt drive play to get this
// information. Note that the first and last track numbers do not
// include the lead-in and lead-out tracks of the session.
//
// The SessionIndex is used to get TOC information from disks
// with more than one recorded session. Sessions are the same
// as OrangeBook Volumes. The first session has a SessionIndex
// of zero, and the second session has a SessionIndex of one.
// A SessionIndex of DISC_INFO_LAST_SESSION (-1) requests the disc
// info for the last session recorded on the disc.
//
// The LogicStartAddr is the logical sector address of the first
// data sector of the first track in this session.
//
// For standard Redbook and Yellowbook CD-ROMs, zero (0) is the
// only valid SessionIndex value. In this case, LogicStartAddr
// should be returned as zero (0).
//
// Note: The LogicStartAddr is normally used to locate the first
// sector of the Volume Recognition Sequence for the indicated
// session. The Volume Recognition Sequence for the session is
// expected to start at Sector (LogicStartAddr + 16).
//
// ENTRY
// IOCTL Packet format specified by CDROM_DISCINFO structure.
// Reserved - Reserved Zero
// SessionIndex - Set to desired session number to query.
// SessionIndex = 0 indicates a query for the first session
// SessionIndex = 0xFFFFFFFF indicates a query for the last
// session on the disc
//
// EXIT
// Success
// Returns NO_ERROR
// CDROM_DISCINFO structure filled in for indicated session
//
// If SessionIndex was passed in as 0xFFFFFFFF, it may be
// modified to contain the index of the last session on the
// disc. Because not all device drivers must scan through
// all the sessions on the disc, this update may or may not
// actually take place.
//
// Failure
// Returns an extended error code.
// ERROR_UNKNOWN_COMMAND - The command is not supported
// ERROR_INVALID_PARAMETER - The session number is invalid
// Other Extended Errors may also be returned
//-----------------------------------------------------------------------------
DWORD CDisk::AtapiGetDiscInfo(PIOREQ pIOReq)
{
// TODO: Support multiple sessions
CDROM_DISCINFO *pDiscInfo = (CDROM_DISCINFO *)pIOReq->pOutBuf;
CDROM_TOC Toc;
DWORD dwError = ERROR_SUCCESS;
return ERROR_SUCCESS; // Bypass for now !!!
if ((pDiscInfo == NULL) ||
(pIOReq->dwOutBufSize< sizeof(CDROM_DISCINFO))) {
return(ERROR_INVALID_PARAMETER);
}
if (AtapiGetToc(&Toc)) {
TRACK_DATA *pTrack = &(Toc.TrackData[0]);
WORD wStartTrack = 0, wLastTrack = 0;
// Find the first & last track of the requested session using the LeadOutTrack to detect
// the session changes
WORD wTrackIndex;
//
// The size or the array is the indicated size minus two bytes. One byte
// for the first track number and one for the last
//
WORD wTOCDataLen = (MAKEWORD(Toc.Length[1], Toc.Length[0]) - 2);
// If there is already a TOC buffer alloacted then see if it is big enough to hold the
// newly read TOC, else allocate a buffer to cache the TOC track info here
WORD wTrackCount = wTOCDataLen/sizeof(TRACK_DATA);
for (wTrackIndex = 0; wTrackIndex < wTrackCount; wTrackIndex++) {
if (pTrack[wTrackIndex].TrackNumber == 0xaa) { // CDATAPI_SESSION_LEADOUT_TRACK = 0xaa
break;
} else {
if( pTrack[wTrackIndex].TrackNumber < wStartTrack)
{
wStartTrack = pTrack[wTrackIndex].TrackNumber;
wStartTrack = wTrackIndex;
}
if( pTrack[wTrackIndex].TrackNumber > wLastTrack)
{
wLastTrack = pTrack[wTrackIndex].TrackNumber;
}
}
}
if (wTrackIndex == wTrackCount) {
dwError = ERROR_IO_DEVICE;
return FALSE;
}
pDiscInfo->FirstTrack = pTrack[wStartTrack].TrackNumber;
pDiscInfo->LastTrack = pTrack[wLastTrack].TrackNumber;
pDiscInfo->LogicStartAddr = CDROM_MSFCOMP_TO_LBA(pTrack[wStartTrack].Address[1], pTrack[wStartTrack].Address[2], pTrack[wStartTrack].Address[3]);
pDiscInfo->LeadOutTrackAddr.msf_Frame = pTrack[wTrackIndex].Address[3];
pDiscInfo->LeadOutTrackAddr.msf_Second = pTrack[wTrackIndex].Address[2];
pDiscInfo->LeadOutTrackAddr.msf_Minute = pTrack[wTrackIndex].Address[1];
pDiscInfo->LeadOutTrackAddr.msf_Filler = 0;
pDiscInfo->FirstSession = 1;
pDiscInfo->LastSession = 1;
pDiscInfo->RetSession = 1;
}
return dwError;
}
BOOL CDisk::AtapiDetectDVD()
{
CDMODE_SENSE_INFO SenseInfo;
ATAPI_COMMAND_PACKET CmdPkt;
SGX_BUF SgBuf;
DWORD dwRet;
memset(&CmdPkt, 0, sizeof(ATAPI_COMMAND_PACKET));
CmdPkt.Opcode = ATAPI_PACKET_CMD_MODE_SENSE;
CmdPkt.Byte_2 = 0x2a; // Get the mech status page
CmdPkt.Byte_7 = 2; // Say 512 bytes, expect only 18
SgBuf.sb_len = sizeof(CDMODE_SENSE_INFO);
SgBuf.sb_buf = (PBYTE) &SenseInfo;
if (AtapiSendCommand(&CmdPkt)) {
if (!AtapiReceiveData(&SgBuf, 1, &dwRet)) {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("AtaGetSenseInfo Failed!!!\r\n")));
return FALSE;
}
} else {
return FALSE;
}
return (SenseInfo.cap.cdvdc_readbits & READCAPS_DVD);
}
void CDisk::AtapiDumpSenseData()
{
CD_SENSE_DATA SenseData;
if (AtapiGetSenseInfo(&SenseData)) {
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT("Sense Info\r\n")));
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" Error Code = 0x%2.2X, Segment Number = %d, Sense Key = 0x%2.2X\r\n"), SenseData.sd_ErrCode, SenseData.sd_SegNum, SenseData.sd_ILI_Key));
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" Information = 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\r\n"), SenseData.sd_Info[0], SenseData.sd_Info[1], SenseData.sd_Info[2], SenseData.sd_Info[3]));
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" Additional Sense Length = %d\r\n"), SenseData.sd_Length));
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" Command Specific Information = 0x%2.2X 0x%2.2X 0x%2.2X 0x%2.2X\r\n"),SenseData.sd_CmdInfo[0], SenseData.sd_CmdInfo[1], SenseData.sd_CmdInfo[2], SenseData.sd_CmdInfo[3]));
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" ASC = 0x%2.2X, ASCQ = 0x%2.2X, FRUC = 0x%2.2X\r\n"), SenseData.sd_SenseCode, SenseData.sd_Qualifier, SenseData.sd_UnitCode));
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" Sense Key Specfic = 0x%2.2X 0x%2.2X 0x%2.2X\r\n"), SenseData.sd_Key1, SenseData.sd_Key2, SenseData.sd_Key3));
} else {
DEBUGMSG( ZONE_CDROM | ZONE_ERROR, (TEXT(" Unable to get CD Sense info\r\n")));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -