mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1189 lines
21 KiB
1189 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
cdapi.c
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
This module implements the routines that set up for
|
|
and use results from calls to the cdaudio driver (scsicdrm.sys).
|
|
This file presents a "mapping layer" so that different
|
|
drivers can take the place of the calls in cdsys.c
|
|
|
|
|
|
Author:
|
|
|
|
|
|
Rick Turner (ricktu) 31-Jan-1992
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#define IN_CDAPI
|
|
|
|
#define TRACK_TYPE_MASK 0x04
|
|
#define AUDIO_TRACK 0x00
|
|
#define DATA_TRACK 0x04
|
|
|
|
|
|
#include "cdsys.h"
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "cdplayer.h"
|
|
|
|
VOID
|
|
NoMediaUpdate(
|
|
IN INT cdrom
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Update user display when it is found that no media
|
|
is in the device.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device was being accessed
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
none
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
if (gDevices[ cdrom ]->State & PLAYING) {
|
|
|
|
//
|
|
// Reset play button to "up"
|
|
//
|
|
|
|
SetOdCntl(ghwndPlay,'U',TRUE);
|
|
|
|
|
|
//
|
|
// reset play event
|
|
//
|
|
|
|
ResetEvent( hPlayEv );
|
|
|
|
}
|
|
|
|
if (gDevices[ cdrom ]->State & PAUSED) {
|
|
|
|
//
|
|
// Reset pause button to "up"
|
|
//
|
|
|
|
SetOdCntl(ghwndPause,'U',TRUE);
|
|
|
|
//
|
|
// reset play event
|
|
//
|
|
|
|
ResetEvent( hPauseEv );
|
|
|
|
}
|
|
|
|
//
|
|
// Re-initialize the disc settings to
|
|
// "virgin" state
|
|
//
|
|
|
|
gDevices[ cdrom ]->State = (NO_CD | STOPPED);
|
|
|
|
TimeAdjustInitialize( cdrom );
|
|
|
|
}
|
|
|
|
VOID
|
|
CheckStatus(
|
|
IN LPSTR szCaller,
|
|
IN DWORD status,
|
|
IN INT cdrom
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Check return code for known bad codes and inform
|
|
user how to correct (if possible) the problem.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
status - return code from opertaion
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
none
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
CHAR s[100];
|
|
|
|
if (status==ERROR_SUCCESS)
|
|
return;
|
|
|
|
switch( status ) {
|
|
|
|
case ERROR_GEN_FAILURE:
|
|
sprintf( s, IdStr( STR_ERR_GEN ), gDevices[cdrom]->drive, szCaller );
|
|
break;
|
|
|
|
case ERROR_NO_MEDIA_IN_DRIVE:
|
|
sprintf( s, IdStr( STR_ERR_NO_MEDIA ), gDevices[cdrom]->drive );
|
|
NoMediaUpdate( cdrom );
|
|
break;
|
|
|
|
case ERROR_UNRECOGNIZED_MEDIA:
|
|
sprintf( s, IdStr( STR_ERR_UNREC_MEDIA ), gDevices[cdrom]->drive );
|
|
if (!(gDevices[cdrom]->State & DATA_CD_LOADED))
|
|
NoMediaUpdate( cdrom );
|
|
break;
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
sprintf( s, IdStr( STR_ERR_NO_DEVICE ), szCaller, gDevices[cdrom]->drive );
|
|
NoMediaUpdate( cdrom );
|
|
break;
|
|
|
|
case ERROR_INVALID_FUNCTION:
|
|
sprintf( s, IdStr( STR_ERR_INV_DEV_REQ ), gDevices[cdrom]->drive );
|
|
break;
|
|
|
|
case ERROR_NOT_READY:
|
|
sprintf( s, IdStr( STR_ERR_NOT_READY ), gDevices[cdrom]->drive );
|
|
NoMediaUpdate( cdrom );
|
|
break;
|
|
|
|
case ERROR_SECTOR_NOT_FOUND:
|
|
sprintf( s, IdStr( STR_ERR_BAD_SEC ), gDevices[cdrom]->drive );
|
|
break;
|
|
|
|
case ERROR_IO_DEVICE:
|
|
sprintf( s, IdStr( STR_ERR_IO_ERROR ), gDevices[cdrom]->drive );
|
|
break;
|
|
|
|
default:
|
|
sprintf( s, IdStr( STR_ERR_DEFAULT ), gDevices[cdrom]->drive, szCaller, status );
|
|
break;
|
|
|
|
}
|
|
|
|
StatusLine( SL_ERROR, s );
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScanForCdromDevices(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Scan through device chain for CDROM devices. For each one
|
|
that is found, allocate storage in the gDevices array and
|
|
fill in fields available at this time.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
none
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
Number of CDROM devices found.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
CHAR DriveRoot[]="A:\\", DevRoot[]="\\\\.\\A:";
|
|
int NumCdroms;
|
|
HANDLE TmpHandle;
|
|
DWORD dwDrives;
|
|
CHAR s[255];
|
|
|
|
|
|
//
|
|
// Find what drive letters are valid
|
|
//
|
|
|
|
dwDrives = GetLogicalDrives();
|
|
|
|
NumCdroms = 0;
|
|
|
|
//
|
|
// Loop through drives letters one by one, checking to see if it's a Cdrom.
|
|
//
|
|
for ( DriveRoot[0]='A'; dwDrives != 0; dwDrives = dwDrives>>1 ) {
|
|
|
|
//
|
|
// If the current DriveLetter Exists and is a Cdrom
|
|
//
|
|
if ( (dwDrives & 0x1) && (GetDriveType(DriveRoot) == DRIVE_CDROM) ) {
|
|
|
|
DevRoot[4] = DriveRoot[0];
|
|
|
|
|
|
if ((NumCdroms < (INT)gNumCdDevices) && (gDevices[NumCdroms]!=NULL)) {
|
|
|
|
LocalFree( (HLOCAL)gDevices[ NumCdroms ] );
|
|
|
|
}
|
|
|
|
gDevices[ NumCdroms ] = (PCDROM)LocalAlloc( LPTR, sizeof( CDROM ) );
|
|
|
|
if (gDevices[ NumCdroms ]==NULL) {
|
|
|
|
sprintf( s, IdStr( STR_NO_RES ), GetLastError() );
|
|
MyFatalExit( s );
|
|
|
|
}
|
|
|
|
gDevices[ NumCdroms ]->drive = DriveRoot[0];
|
|
gDevices[ NumCdroms ]->State = NO_CD;
|
|
|
|
|
|
//
|
|
// Open the Cdrom for exclusive access
|
|
//
|
|
TmpHandle = CreateFile( DevRoot,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (TmpHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
gDevices[ NumCdroms ]->hCd = NULL;
|
|
|
|
} else {
|
|
|
|
gDevices[ NumCdroms ]->hCd = TmpHandle;
|
|
|
|
}
|
|
|
|
NumCdroms++;
|
|
|
|
}
|
|
|
|
DriveRoot[0] = DriveRoot[0]+1;
|
|
|
|
}
|
|
|
|
return(NumCdroms);
|
|
|
|
|
|
/****************************************************************
|
|
DWORD status;
|
|
TCHAR s[ 16 ];
|
|
ULONG cdDevice = 0;
|
|
HANDLE TmpHandle;
|
|
int cdnum = 0;
|
|
|
|
//
|
|
// Scan drive chain ("a:" thru "z:") for cdrom drives
|
|
//
|
|
|
|
for( cdDevice=0; cdDevice<26; cdDevice++ ) {
|
|
|
|
sprintf( s, "\\\\.\\%c:", cdDevice + (INT)'A' );
|
|
if (GetDriveType( &s[4*sizeof(TCHAR)] )==DRIVE_CDROM) {
|
|
|
|
TmpHandle = CreateFile( s,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (TmpHandle!=INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// Found cdrom drive!
|
|
//
|
|
|
|
if ((cdnum<(INT)gNumCdDevices) && (gDevices[ cdnum ]!=NULL))
|
|
LocalFree( (HLOCAL)gDevices[ cdnum ] );
|
|
gDevices[ cdnum ] = (PCDROM)LocalAlloc( LPTR, sizeof( CDROM ) );
|
|
if (gDevices[ cdnum ]==NULL)
|
|
MyFatalExit( IdStr( STR_NO_RES ) );
|
|
gDevices[ cdnum ]->hCd = TmpHandle;
|
|
gDevices[ cdnum ]->drive = (CHAR)(cdDevice + (INT)'A');
|
|
gDevices[ cdnum ]->State = NO_CD;
|
|
cdnum++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return( cdnum );
|
|
|
|
***************************************************************/
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReadTOC(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Try to read table of contents from disc in cdrom device.
|
|
Check return code and set "State" bits accordingly.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if TOC read was successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
// NTSTATUS status;
|
|
DWORD status;
|
|
UCHAR num,i,numaudio;
|
|
CHAR s[15];
|
|
|
|
//
|
|
// Try to read the TOC from the drive.
|
|
//
|
|
|
|
status = GetCdromTOC( gDevices[ cdrom ]->hCd, &(gDevices[cdrom]->toc) );
|
|
|
|
//
|
|
// Need to check if we got data tracks or audio
|
|
// tracks back...if there is a mix, strip out
|
|
// the data tracks...
|
|
//
|
|
|
|
num = gDevices[cdrom]->toc.LastTrack - gDevices[cdrom]->toc.FirstTrack+1;
|
|
|
|
if (status==ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Look for audio tracks...
|
|
//
|
|
|
|
numaudio = 0;
|
|
for( i=0; i<num; i++ ) {
|
|
|
|
if ((gDevices[cdrom]->toc.TrackData[i].Control & TRACK_TYPE_MASK)==AUDIO_TRACK)
|
|
numaudio++;
|
|
|
|
}
|
|
|
|
//
|
|
// If there aren't any audio tracks, then we (most likely)
|
|
// have a data CD loaded.
|
|
//
|
|
|
|
if (numaudio==0) {
|
|
|
|
status == ERROR_UNRECOGNIZED_MEDIA;
|
|
gDevices[ cdrom ]->State = DATA_CD_LOADED | STOPPED;
|
|
|
|
} else {
|
|
|
|
gDevices[ cdrom ]->State = CD_LOADED | STOPPED;
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
//
|
|
// We will get a STATUS_VERIFY_REQUIRED if the media has
|
|
// changed and a verify operation is in progress, so
|
|
// retry until we either succeed or fail...
|
|
//
|
|
// FIXFIX Unfortunately, there is no Win32 error code for
|
|
// STATUS_VERIFY_REQUIRED.
|
|
//
|
|
|
|
/*
|
|
if (status==STATUS_VERIFY_REQUIRED) {
|
|
|
|
//
|
|
// Give device some more time, and try again
|
|
//
|
|
|
|
Sleep( 100 );
|
|
return( ReadTOC( cdrom ) );
|
|
|
|
} else {
|
|
*/
|
|
gDevices[ cdrom ]->State = NO_CD | STOPPED;
|
|
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
sprintf( s, "ReadTOC(%d)", cdrom );
|
|
CheckStatus( s, status, cdrom );
|
|
return(status==ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
PlayCurrTrack(
|
|
INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Set cdrom device playing from start MSF to end MSF of current
|
|
track.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if play was successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
CDROM_PLAY_AUDIO_MSF pam;
|
|
int retry,min,sec,endindex;
|
|
INT i;
|
|
PTRACK_PLAY tr;
|
|
|
|
tr = CURRTRACK( cdrom );
|
|
if (tr==NULL) {
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
sec = TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec;
|
|
min = TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin;
|
|
min += (sec / 60);
|
|
sec = (sec % 60);
|
|
pam.StartingM = min;
|
|
pam.StartingS = sec;
|
|
pam.StartingF = TRACK_F(cdrom,tr->TocIndex);
|
|
|
|
endindex = FindContiguousEnd( cdrom, tr );
|
|
|
|
pam.EndingM = TRACK_M(cdrom,endindex);
|
|
pam.EndingS = TRACK_S(cdrom,endindex);
|
|
pam.EndingF = TRACK_F(cdrom,endindex);
|
|
|
|
//
|
|
// for some reason, sometimes the lead out track
|
|
// gived bad values, because when we try to
|
|
// play the last track, we get an error. However,
|
|
// if we back up a little bit from what is reported
|
|
// to us as the end of the last track, we can get
|
|
// it to play. Below is a hack to do just that...
|
|
//
|
|
|
|
|
|
retry = 0;
|
|
|
|
do {
|
|
|
|
status = PlayCdrom( gDevices[ cdrom ]->hCd, &pam );
|
|
|
|
if ( (status != ERROR_SUCCESS)
|
|
) {
|
|
|
|
//
|
|
// Didn't play, so try backing off a little bit
|
|
// at the end of the track
|
|
//
|
|
|
|
retry++;
|
|
|
|
i = (INT)pam.EndingF - 30;
|
|
if (i<0) {
|
|
|
|
pam.EndingF = (UCHAR)(70 + i);
|
|
|
|
if (pam.EndingS!=0) {
|
|
|
|
pam.EndingS--;
|
|
|
|
} else {
|
|
|
|
pam.EndingS=59;
|
|
pam.EndingM--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pam.EndingF = (UCHAR)i;
|
|
|
|
}
|
|
|
|
//
|
|
// Store the information in our structures so that
|
|
// we don't have to recompute this next time...
|
|
//
|
|
|
|
TRACK_M(cdrom,endindex) = pam.EndingM;
|
|
TRACK_S(cdrom,endindex) = pam.EndingS;
|
|
TRACK_F(cdrom,endindex) = pam.EndingF;
|
|
|
|
} else
|
|
|
|
retry = 15;
|
|
|
|
} while ((retry<15) && (status!=ERROR_SUCCESS));
|
|
|
|
CheckStatus( "PlayCurrTrack", status, cdrom );
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
ValidatePosition( cdrom );
|
|
|
|
}
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
StopTheCdromDrive(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Tell the cdrom device to stop playing
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if stop was successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
|
|
status = StopCdrom( gDevices[cdrom]->hCd );
|
|
|
|
CheckStatus( "StopCdrom", status, cdrom );
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
BOOL
|
|
PauseTheCdromDrive(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Tell the cdrom device to pause playing
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if pause was successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
|
|
status = PauseCdrom( gDevices[ cdrom ]->hCd );
|
|
|
|
CheckStatus( "PauseCdrom", status, cdrom );
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
BOOL
|
|
ResumeTheCdromDrive(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Tell the cdrom device to resume playing
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if resume was successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
|
|
status = ResumeCdrom( gDevices[ cdrom ]->hCd );
|
|
|
|
CheckStatus( "ResumeCdrom", status, cdrom );
|
|
if (status==ERROR_NOT_READY)
|
|
NoMediaUpdate( cdrom );
|
|
else
|
|
ValidatePosition( cdrom );
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
BOOL
|
|
SeekToCurrSecond(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Seek to the position on the disc represented by the
|
|
current time (position) information in gDevices, and
|
|
continue playing to the end of the current track.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if seek was successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
CDROM_PLAY_AUDIO_MSF pam;
|
|
int retry,i,endindex;
|
|
PTRACK_PLAY tr;
|
|
SUB_Q_CHANNEL_DATA subq;
|
|
CDROM_SUB_Q_DATA_FORMAT df;
|
|
|
|
//
|
|
// Build starting and ending positions for play
|
|
//
|
|
|
|
tr = CDTIME(cdrom).CurrTrack;
|
|
if (tr==NULL) {
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
//
|
|
// This routine sometimes wants to play from the current position
|
|
// through the end of the contiguous play. Since the current
|
|
// position is only being stored accurate down to seconds, we get
|
|
// the current position, see if it's reasonably close to our
|
|
// starting position, then start the play from the actual current
|
|
// position.
|
|
//
|
|
|
|
df.Format = IOCTL_CDROM_CURRENT_POSITION;
|
|
df.Track = (UCHAR)CDTIME(cdrom).CurrTrack->TocIndex;
|
|
GetCdromSubQData( gDevices[ cdrom ]->hCd, &subq, &df );
|
|
|
|
pam.StartingM = (UCHAR)(TRACK_M(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurMin);
|
|
pam.StartingS = (UCHAR)(TRACK_S(cdrom,tr->TocIndex) + CDTIME(cdrom).TrackCurSec);
|
|
pam.StartingF = 0;
|
|
|
|
i = pam.StartingM * 60 + pam.StartingS;
|
|
i-= (INT) subq.CurrentPosition.AbsoluteAddress[1] * 60;
|
|
i-= (INT) subq.CurrentPosition.AbsoluteAddress[2];
|
|
|
|
|
|
if (ABS(i) <= 1) {
|
|
|
|
pam.StartingM = (INT) subq.CurrentPosition.AbsoluteAddress[1];
|
|
pam.StartingS = (INT) subq.CurrentPosition.AbsoluteAddress[2];
|
|
pam.StartingF = (INT) subq.CurrentPosition.AbsoluteAddress[3];
|
|
|
|
}
|
|
|
|
|
|
if (pam.StartingS > 59) {
|
|
pam.StartingM++;
|
|
pam.StartingS = (UCHAR)(pam.StartingS - 60);
|
|
}
|
|
|
|
if ((CDTIME(cdrom).TrackCurMin==0) && (CDTIME(cdrom).TrackCurSec==0))
|
|
pam.StartingF = TRACK_F(cdrom,tr->TocIndex);
|
|
|
|
if (gDevices[ cdrom ]->State & PLAYING) {
|
|
|
|
endindex = FindContiguousEnd( cdrom, tr );
|
|
|
|
pam.EndingM = TRACK_M(cdrom,endindex);
|
|
pam.EndingS = TRACK_S(cdrom,endindex);
|
|
pam.EndingF = TRACK_F(cdrom,endindex);
|
|
|
|
} else {
|
|
|
|
pam.EndingM = pam.StartingM;
|
|
pam.EndingS = pam.StartingS;
|
|
pam.EndingF = pam.StartingF;
|
|
|
|
}
|
|
|
|
retry = 0;
|
|
|
|
do {
|
|
|
|
status = PlayCdrom( gDevices[ cdrom ]->hCd, &pam );
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Didn't play, so try backing off a little bit
|
|
// at the end of the track
|
|
//
|
|
|
|
retry++;
|
|
|
|
i = (INT)pam.EndingF - 30;
|
|
if (i<0) {
|
|
|
|
pam.EndingF = (UCHAR)(70 + i);
|
|
|
|
if (pam.EndingS!=0) {
|
|
|
|
pam.EndingS--;
|
|
|
|
} else {
|
|
|
|
pam.EndingS=59;
|
|
pam.EndingM--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pam.EndingF = (UCHAR)i;
|
|
|
|
}
|
|
|
|
//
|
|
// Store the information in our structures so that
|
|
// we don't have to recompute this next time...
|
|
//
|
|
|
|
TRACK_M(cdrom,endindex) = pam.EndingM;
|
|
TRACK_S(cdrom,endindex) = pam.EndingS;
|
|
TRACK_F(cdrom,endindex) = pam.EndingF;
|
|
|
|
} else
|
|
|
|
retry = 15;
|
|
|
|
} while ((retry<15) && (status!=ERROR_SUCCESS));
|
|
|
|
CheckStatus( "SeekToCurrSec", status, cdrom );
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
ValidatePosition(cdrom);
|
|
|
|
}
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetCurrPos(
|
|
IN INT cdrom,
|
|
OUT PCURRPOS CpPtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Query cdrom device for its current position and status
|
|
and return information in callers buffer.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
CpPtr - pointer to caller allocated storage which will
|
|
hold results of our query.
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
SUB_Q_CHANNEL_DATA subq;
|
|
CDROM_SUB_Q_DATA_FORMAT df;
|
|
|
|
//
|
|
// Tell lower layer what we want it to do...in this case,
|
|
// we need to specify which SubQData format we want returned.
|
|
// This is exported from scsicdrom.sys to the user layer
|
|
// so that it could be implemented in one call, instead of
|
|
// four separate calls (there are four SubQData formats)
|
|
//
|
|
|
|
//
|
|
// Set up for current position SubQData format.
|
|
//
|
|
|
|
df.Format = IOCTL_CDROM_CURRENT_POSITION;
|
|
if (CDTIME(cdrom).CurrTrack != NULL) {
|
|
|
|
df.Track = (UCHAR)CDTIME(cdrom).CurrTrack->TocIndex;
|
|
status = GetCdromSubQData( gDevices[ cdrom ]->hCd, &subq, &df );
|
|
|
|
} else {
|
|
|
|
status = (DWORD) ~ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
if (status==ERROR_SUCCESS) {
|
|
|
|
CpPtr->AudioStatus = subq.CurrentPosition.Header.AudioStatus;
|
|
CpPtr->Track = (INT)subq.CurrentPosition.TrackNumber;
|
|
CpPtr->Index = (INT)subq.CurrentPosition.IndexNumber;
|
|
CpPtr->m = (INT)subq.CurrentPosition.TrackRelativeAddress[1];
|
|
CpPtr->s = (INT)subq.CurrentPosition.TrackRelativeAddress[2];
|
|
CpPtr->f = (INT)subq.CurrentPosition.TrackRelativeAddress[3];
|
|
CpPtr->ab_m = (INT)subq.CurrentPosition.AbsoluteAddress[1];
|
|
CpPtr->ab_s = (INT)subq.CurrentPosition.AbsoluteAddress[2];
|
|
CpPtr->ab_f = (INT)subq.CurrentPosition.AbsoluteAddress[3];
|
|
|
|
} else {
|
|
|
|
CpPtr->AudioStatus = 0;
|
|
CpPtr->Track = 0;
|
|
CpPtr->Index = 0;
|
|
CpPtr->m = 0;
|
|
CpPtr->s = 0;
|
|
CpPtr->f = 0;
|
|
CpPtr->ab_m = 0;
|
|
CpPtr->ab_s = 0;
|
|
CpPtr->ab_f = 0;
|
|
|
|
}
|
|
|
|
CheckStatus( "GetCurrPos", status, cdrom );
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
BOOL
|
|
SeekToTrackAndHold(
|
|
IN INT cdrom,
|
|
IN INT tindex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Seek to specified track and enter hold state.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
track - track on audio cd to seek to.
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
CDROM_SEEK_AUDIO_MSF sam;
|
|
|
|
sam.M = TRACK_M(cdrom,tindex);
|
|
sam.S = TRACK_S(cdrom,tindex);
|
|
sam.F = TRACK_F(cdrom,tindex);
|
|
|
|
status = SeekCdrom( gDevices[ cdrom ]->hCd, &sam );
|
|
|
|
CheckStatus( "SeekToTrackAndHold", status, cdrom );
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
ValidatePosition( cdrom );
|
|
|
|
}
|
|
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
BOOL
|
|
EjectTheCdromDisc(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Eject the disc from the specified cdrom device.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if successful, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
|
|
//
|
|
// Stop the drive first
|
|
//
|
|
|
|
status = StopCdrom( gDevices[cdrom]->hCd );
|
|
|
|
//
|
|
// Eject the disc
|
|
//
|
|
|
|
status = EjectCdrom( gDevices[cdrom]->hCd );
|
|
|
|
CheckStatus( "EjectCdrom", status, cdrom );
|
|
|
|
return( status==ERROR_SUCCESS );
|
|
|
|
}
|
|
|
|
VOID
|
|
CheckUnitCdrom(
|
|
IN INT cdrom
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Queries the device state, checking to see if a cartridge has
|
|
been ejected or inserted.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
cdrom - index into gDevices array, specifies which CDROM
|
|
device to access
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
none.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD status;
|
|
CHAR s[50];
|
|
|
|
|
|
status = TestUnitReadyCdrom( gDevices[cdrom]->hCd );
|
|
|
|
if (gDevices[cdrom]->State & NO_CD) {
|
|
|
|
if (status==ERROR_SUCCESS) {
|
|
|
|
//
|
|
// a new disc has been inserted. Scan it now.
|
|
//
|
|
|
|
sprintf( s, IdStr( STR_DISC_INSERT ), cdrom );
|
|
StatusLine( SL_INFO, s );
|
|
RescanDevice( cdrom );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (status!=ERROR_SUCCESS) {
|
|
|
|
//
|
|
// a disc has been ejected
|
|
//
|
|
|
|
sprintf( s, IdStr( STR_DISC_EJECT ), cdrom );
|
|
StatusLine( SL_INFO, s );
|
|
NoMediaUpdate( cdrom );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|