home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cdrom.zip
/
DDK
/
BASE
/
SRC
/
VDEV
/
VCDROM
/
vcdrom2f.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-18
|
50KB
|
1,439 lines
/**************************************************************************
*
* SOURCE FILE NAME = VCDROM2F.C
*
* DESCRIPTIVE NAME = VCDROM MSCDEX 2F support for CD-ROM in a DOS session.
*
* DESCRIPTION This module contains the (MSCDEX) int 2fh and DOS CD-ROM
* device driver service routines.
*
* Copyright : COPYRIGHT IBM CORPORATION, 1991, 1992
* Copyright Microsoft Corporation, 1990
* LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
* REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
* RESTRICTED MATERIALS OF IBM
* IBM CONFIDENTIAL
*
* ENTRY POINTS:
* VCDROMDosLink
* SendDeviceRequest
* ResetMedia
* GetDriveHandle
* MapOS2toDosCode
* GetPlayStatus
* HsgToRedbook
* AddSectors
*
* EXTERNAL REFERENCES:
*
* CHANGE ACTIVITY =
* DATE FLAG APAR CHANGE DESCRIPTION
* -------- ---------- ----- --------------------------------------
* mm/dd/yy @Vr.mpppxx xxxxx xxxxxxx
* 08/16/91 @V2.0DTF Created.
*
* 09/26/92 @V2.1FJS00 Added MSCDEX 0x2f calls previously not
* supported. Converted VCDROMDosLink from
* 0x66 to 0x2f routine.
*
* 03/34/92 @V2.1FJS01 Deleted message includes in reqhdr.h and added
* systemwide bseerr.h. Added media check for
* MSCDEX api. Could have done open/close around
* each VDHFSCtl call but too much performance
* penalty.
*
* 04/12/93 @V2.1FJS02 Removed VdhQueryLin call from MSCDEX calls
* since segment portion of pointers can only be
* real mode segment value (per MSCDEX 2.21 spec).
*
* 08/06/93 @V2.1FJS03 Changed Absolute Disk Read to clear carry flag
* and set AX=0 when function succeeds for Bible
* Library Version 1.1. MSCDEX specification does
* not require AX=0.
*
* 04/04/95 @V113078 Allow raw Read_Longs. These Read_Longs do use
* the File System as they are non-standard
* sector sizes (2352). However, there is a
* direct IOCTL to the device manager to read
* this type of sector (Cat 80 Fun 72)
*
****************************************************************************/
#define INCL_DOSERRORS
#include <bseerr.h>
#include <mvdm.h>
#include <mscdex.h>
#include "vcdromp.h"
#include "reqhdr.h"
#include "ctrlblk.h"
#ifdef VDDSTRICT
MODNAME = __FILE__;
#endif
/*
** External References
*/
/*
** Global Data
*/
extern
BOOL flSLAVE;
extern
PFN pfnSlaveRequest;
extern
struct
CategoryCode
IoctlInputCodes [];
extern
struct
CategoryCode
IoctlOutputCodes [];
extern
USHORT NumberOfDrives;
extern
USHORT FirstDriveNumber;
extern
HFILE
DriveHandle [MAX_NUMBER_OF_DRIVES]; /* DASD-open drive handles */
extern
UCHAR
DriveString []; /* Drive letter strings */
extern
VPDOSDDTYPE DosDDHeader; /* V86FAR address of dos driver */
/*
** Instance Data
*/
extern
HVDM hvdmCurrent;
extern
ULONG slaveparms [];
extern
ULONG DataArea[];
extern
ULONG ParmList[];
extern
ULONG DataLengthInOut;
extern
ULONG ParmLengthInOut;
extern
HFILE FileHandle; /* for VDHOpen */
extern
ULONG ActionTaken; /* for VDHOpen */
#pragma BEGIN_GLOBAL_CODE
#pragma END_GLOBAL_CODE
#pragma BEGIN_SWAP_CODE
/****************************************************************************
*
* FUNCTION NAME = VCDROMDosLink
*
* DESCRIPTION = Handle MSCDEX 2f interrupts ( AH == 15h )
*
* The DOS stub device driver hooks the MSCDEX 2f interrupts and
* calls this function by use of an ARPL instruction.
*
* Some MSCDEX (DOS CD-ROM file system driver) 2f services are
* implemented here others by the OS/2 CD-ROM installable file
* system (CDROM.IFS). VCDROM calls the installable file system
* via the VDHFSCtl service.
*
* MSCDEX API parameters must be real mode addresses (per the
* MSCDEX 2.21 Specification).
*
* Audio and other ioctls are supported through Send Driver Request.
* The app formats an ioctl input or ioctl output DOS driver request
* packet to be forwarded to the CD-ROM device driver for service.
* The format of these requests is described in the Microsoft
* MSCDEX spec. The method used here is to convert the DOS request
* into an OS/2 generic ioctl that is sent to the OS/2 CD-ROM device
* driver through the VDHDevIOCtl call. The format of the OS/2 CD-ROM
* ioctls is described in the CDFS (OS/2 file system driver) spec.
*
* Some DOS apps (Groliers) bypass MSCDEX, calling the dos driver
* directly. The DOS stub converts these requests into 2f Send Driver
* Request format for consistency.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* VDHPopInt to prevent ROM code execution.
* If MSCDEX function 10h, call SendDeviceRequest,
* otherwise either call the installable file system for service
* or service it here.
*
* INPUT = pcrf - pointer to client register frame
*
* OUTPUT = returns TRUE == serviced interrupt
* returns FALSE == not mine
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
BOOL HOOKENTRY VCDROMDosLink (PVOID pHookData, register PCRF pcrf)
{
register
struct
DosRh *reqhdr; /* dos request header */
register
PUCHAR buffer;
PUCHAR szpathname; /* ptr to path name */
USHORT i; /* counter */
PUCHAR ptmp1; /* temp ptr */
ULONG drive_number;
ULONG n;
ULONG rc;
PULONG vdd_name;
HFILE handle;
ULONG sector_index;
/* INT_3; */
VDHPopInt(); /* to prevent ROM code execution */
if ( AL (pcrf) == SEND_DEVICE_REQUEST )
{
reqhdr = PFROMVADDR ( ES (pcrf), BX (pcrf) );
drive_number = CX (pcrf);
if ( drive_number == 0 ) /* 0 = no drive number */
{
drive_number = UNIT_TO_DRIVE_NUMBER ( reqhdr->subunit );
}
SendDeviceRequest ( reqhdr, drive_number );
}
else /* infrequent 2f services */
{
switch ( AL (pcrf) )
{
case GET_NUMBER_CDROM_DRIVE_LETTERS:
BX (pcrf) = NumberOfDrives;
CX (pcrf) = FirstDriveNumber;
break;
case GET_CDROM_DRIVE_DEVICE_LIST:
buffer = PFROMVADDR ( ES (pcrf), BX (pcrf) );
for ( n = 0; n < NumberOfDrives; ++n )
{
*buffer = (UCHAR) n; /* subunit number */
++buffer;
* ((PULONG) buffer) = (ULONG) DosDDHeader;
buffer += 4;
}
break;
case GET_COPYRIGHT_FILE_NAME:
case GET_ABSTRACT_FILE_NAME:
case GET_BIBLIOGRAPHIC_FILE_NAME:
/*
** get VDHOpen handle to CD-ROM drive specified in CX
*/
drive_number = CX (pcrf);
handle = GetDriveHandle (drive_number);
if (handle == NULL)
{
AX (pcrf) = ERROR_I24_WRONG_DISK; // INVALID_DRIVE
FL (pcrf) |= CARRY_FLAG;
break;
}
/*
** convert virtual address to 0:32 flat address
*/
buffer = (PUCHAR)((ULONG)PFROMVADDR(ES(pcrf),BX(pcrf))+
(ULONG)hvdmCurrent);
/* set user buffer length */
DataLengthInOut=MAX_FILE_ID_LEN;
/* set MSCDEX function code */
((PGETFILE)ParmList)->ulFunction=(ULONG)AL(pcrf);
/* set structure length */
ParmLengthInOut=sizeof(GETFILE);
/*
** call CD-ROM IFS for file name
*/
rc = VDHFSCtl((PVOID)buffer,
(ULONG)DataLengthInOut,
(PVOID)&DataLengthInOut,
(PVOID)&ParmList,
(ULONG)ParmLengthInOut,
(PVOID)&ParmLengthInOut,
(ULONG)FSCTL_ARG_MSCDEX,
(PSZ)NULL,
handle,
FSCTL_HANDLE);
if ( rc == VDH_FAILURE )
{
rc = VDHGetError ();
AX (pcrf) = ERROR_I24_NOT_READY; // DRIVE_NOT_READY
FL (pcrf) |= CARRY_FLAG;
break;
}
FL (pcrf) &= ~CARRY_FLAG;
break;
case READ_VTOC:
/*
** get VDHOpen handle to CD-ROM drive specified in CX
*/
drive_number = CX (pcrf);
handle = GetDriveHandle (drive_number);
if (handle == NULL)
{
AX (pcrf) = ERROR_I24_WRONG_DISK; // INVALID_DRIVE
FL (pcrf) |= CARRY_FLAG;
break;
}
/*
** convert virtual address to 0:32 flat address
*/
buffer = (PUCHAR)((ULONG)PFROMVADDR(ES(pcrf),BX(pcrf))+
(ULONG)hvdmCurrent);
/* set user buffer length */
DataLengthInOut=CDROM_SECTOR_SIZE;
/* set MSCDEX function code */
((PREADVTOC)ParmList)->ulFunction=(ULONG)AL(pcrf);
/* set MSCDEX sector index */
((PREADVTOC)ParmList)->ulSectorIndex=(ULONG)DX(pcrf);
/* set structure length */
ParmLengthInOut=sizeof(READVTOC);
/*
** call CD-ROM IFS to read VTOC
*/
rc = VDHFSCtl((PVOID)buffer,
(ULONG)DataLengthInOut,
(PVOID)&DataLengthInOut,
(PVOID)&ParmList,
(ULONG)ParmLengthInOut,
(PVOID)&ParmLengthInOut,
(ULONG)FSCTL_ARG_MSCDEX,
(PSZ)NULL,
handle,
FSCTL_HANDLE);
if ( rc == VDH_FAILURE )
{
rc = VDHGetError ();
AX (pcrf) = ERROR_I24_NOT_READY; // DRIVE_NOT_READY
FL (pcrf) |= CARRY_FLAG;
break;
}
else
{
if (*(PUCHAR)ParmList == STANDARD_VOLUME_DESCRIPTOR)
AX (pcrf) = STANDARD_VOLUME_DESCRIPTOR;
else
{
if (*(PUCHAR)ParmList == VOLUME_DESCRIPTOR_TERMINATOR)
AX (pcrf) = VOLUME_DESCRIPTOR_TERMINATOR;
else
AX (pcrf) = OTHER_VOLUME_DESCRIPTOR;
}
FL (pcrf) &= ~CARRY_FLAG;
}
break;
case ABSOLUTE_DISK_READ:
/*
** get VDHOpen handle to CD-ROM drive specified in CX
*/
drive_number = CX (pcrf);
handle = GetDriveHandle (drive_number);
if (handle == NULL)
{
AX (pcrf) = ERROR_I24_WRONG_DISK; // INVALID_DRIVE
FL (pcrf) |= CARRY_FLAG;
break;
}
/*
** convert virtual address to 0:32 flat address
*/
buffer = (PUCHAR)((ULONG)PFROMVADDR(ES(pcrf),BX(pcrf))+
(ULONG)hvdmCurrent);
/* set user buffer length */
DataLengthInOut=CDROM_SECTOR_SIZE * DX(pcrf);
/* set MSCDEX function code */
((PABSREAD)ParmList)->ulFunction=(ULONG)AL(pcrf);
/* set MSCDEX sector count */
((PABSREAD)ParmList)->ulSectorCount=(ULONG)DX(pcrf);
/* set MSCDEX sector start */
((PABSREAD)ParmList)->usSectStartLo=DI(pcrf);
/* set MSCDEX sector start */
((PABSREAD)ParmList)->usSectStartHi=SI(pcrf);
/* set structure length */
ParmLengthInOut=sizeof(ABSREAD);
if (flSLAVE) /* if INT_DURING_IO property */
{
slaveparms[0] = (ULONG)buffer;
slaveparms[1] = DataLengthInOut;
slaveparms[2] = (ULONG)&DataLengthInOut;
slaveparms[3] = (ULONG)&ParmList;
slaveparms[4] = ParmLengthInOut;
slaveparms[5] = (ULONG)&ParmLengthInOut;
slaveparms[6] = FSCTL_ARG_MSCDEX;
slaveparms[7] = NULL;
slaveparms[8] = (ULONG)handle;
slaveparms[9] = FSCTL_HANDLE;
pcrf->crf_eax = (ULONG)&slaveparms[0]; /* pass parameters */
pfnSlaveRequest (pcrf); /* call slave thread */
}
else
{
/*
** call CD-ROM IFS for ABSOLUTE DISK READ
*/
rc = VDHFSCtl((PVOID)buffer,
(ULONG)DataLengthInOut,
(PVOID)&DataLengthInOut,
(PVOID)&ParmList,
(ULONG)ParmLengthInOut,
(PVOID)&ParmLengthInOut,
(ULONG)FSCTL_ARG_MSCDEX,
(PSZ)NULL,
handle,
FSCTL_HANDLE);
if ( rc == VDH_FAILURE )
{
rc = VDHGetError ();
AX (pcrf) = ERROR_I24_NOT_READY; // DRIVE_NOT_READY
FL (pcrf) |= CARRY_FLAG;
break;
}
} /* endif */
/* successful return. */
AX (pcrf) = NO_ERROR;
FL (pcrf) &= ~CARRY_FLAG;
break;
case ABSOLUTE_DISK_WRITE:
break;
case CDROM_DRIVE_CHECK:
BX (pcrf) = MSCDEX_SIGNATURE;
drive_number = CX (pcrf);
if ( drive_number < FirstDriveNumber ||
drive_number >= FirstDriveNumber + NumberOfDrives )
{
AX (pcrf) = 0;
}
break;
case GET_MSCDEX_VERSION:
BX (pcrf) = MSCDEX_VERSION;
break;
case GET_CDROM_DRIVE_LETTERS:
buffer = PFROMVADDR ( ES (pcrf), BX (pcrf) );
for ( n = 0; n < NumberOfDrives; ++n )
{
*buffer = (UCHAR) ( FirstDriveNumber + n );
++buffer;
}
break;
case VOLUME_DESCRIPTOR_PREFERENCE:
/*
** get VDHOpen handle to CD-ROM drive specified in CX
*/
drive_number = CX (pcrf);
handle = GetDriveHandle (drive_number);
if (handle == NULL)
{
AX (pcrf) = ERROR_I24_WRONG_DISK; // INVALID_DRIVE
FL (pcrf) |= CARRY_FLAG;
break;
}
/* set MSCDEX function code */
((PVOLDESCPREF)ParmList)->ulFunction=(ULONG)AL(pcrf);
/* set MSCDEX get/set pref request */
((PVOLDESCPREF)ParmList)->ulPrefReq=(ULONG)BX(pcrf);
/* set MSCDEX get/set pref value */
((PVOLDESCPREF)ParmList)->ulPrefVal=(ULONG)DX(pcrf);
/* set structure length */
ParmLengthInOut=sizeof(VOLDESCPREF);
/* set user buffer length */
DataLengthInOut=0;
/*
** call CD-ROM IFS for GET DIRECTORY ENTRY
*/
rc = VDHFSCtl((PVOID)buffer,
(ULONG)DataLengthInOut,
(PVOID)&DataLengthInOut,
(PVOID)&ParmList,
(ULONG)ParmLengthInOut,
(PVOID)&ParmLengthInOut,
(ULONG)FSCTL_ARG_MSCDEX,
(PSZ)NULL,
handle,
FSCTL_HANDLE);
if ( rc == VDH_FAILURE )
{
rc = VDHGetError ();
AX (pcrf) = (USHORT) rc;
FL (pcrf) |= CARRY_FLAG;
break;
}
/*
** return volume descriptor preference
*/
if (BX(pcrf) == GET_VOL_DESC_PREF)
DX(pcrf) = (USHORT)((PVOLDESCPREF)ParmList)->ulPrefVal;
FL (pcrf) &= ~CARRY_FLAG;
break;
case GET_DIRECTORY_ENTRY:
/*
** get VDHOpen handle to CD-ROM drive specified in CH
*/
drive_number = CL (pcrf);
handle = GetDriveHandle (drive_number);
if (handle == NULL)
{
AX (pcrf) = ERROR_I24_WRONG_DISK; // INVALID_DRIVE
FL (pcrf) |= CARRY_FLAG;
break;
}
/*
** Directory Entry buffer
** convert virtual address to 0:32 flat address
*/
buffer = (PUCHAR)((ULONG)PFROMVADDR(SI(pcrf),DI(pcrf))+
(ULONG)hvdmCurrent);
if (CH(pcrf) == 0) /* set user buffer length */
DataLengthInOut=DIR_ENTRY_SPECIFIC_LEN;
else /* set user buffer length */
DataLengthInOut=DIR_ENTRY_GENERAL_LEN;
/*
** ASCIIZ filename buffer
** convert virtual address to 0:32 flat address
*/
szpathname = PFROMVADDR(ES(pcrf),BX(pcrf));
/* set MSCDEX function code */
((PGETDIRENTRY)ParmList)->ulFunction=(ULONG)AL(pcrf);
/* set MSCDEX copy flags */
((PGETDIRENTRY)ParmList)->ulFlags=(ULONG)CH(pcrf);
i=0;
ptmp1=(PUCHAR)ParmList; /* get ptr to variable part */
ptmp1+=sizeof(GETDIRENTRY);
do
{
*ptmp1=*szpathname;
ptmp1++;
szpathname++;
i++;
} while (*(szpathname-1) != NULL); /* enddo */
/* set structure length */
ParmLengthInOut=(ULONG)(i+sizeof(GETDIRENTRY));
/*
** call CD-ROM IFS for GET DIRECTORY ENTRY
*/
rc = VDHFSCtl((PVOID)buffer,
(ULONG)DataLengthInOut,
(PVOID)&DataLengthInOut,
(PVOID)&ParmList,
(ULONG)ParmLengthInOut,
(PVOID)&ParmLengthInOut,
(ULONG)FSCTL_ARG_MSCDEX,
(PSZ)NULL,
handle,
FSCTL_HANDLE);
if ( rc == VDH_FAILURE )
{
rc = VDHGetError ();
AX (pcrf) = (USHORT) rc;
FL (pcrf) |= CARRY_FLAG;
break;
} else
/* High Sierra = 0, ISO-9660 = 1 */
AX (pcrf) = (USHORT)((PGETDIRENTRY)ParmList)->ulFlags;
FL (pcrf) &= ~CARRY_FLAG;
break;
default:
AX (pcrf) = ERROR_INVALID_2F_FUNCTION;
FL (pcrf) |= CARRY_FLAG;
}
}
return TRUE; /* claimed the interrupt */
}
/****************************************************************************
*
* FUNCTION NAME = SendDeviceRequest
*
* DESCRIPTION = SendDeviceRequest to the OS/2 driver
*
* This function converts the supported DOS driver request packets
* to VDHDevIOCtl calls and directs them to the OS/2 CD-ROM device
* driver.
*
* COMPARISON OF PARAM/DATA AREAS
*
* DOS PARAMS DOS DATA OS/2 PARAMS
* ------------ ------------ --------------
* C
* D
* 0
* command code 1
* param byte 1 data byte 1 param byte 1
* param byte 2 data byte 1 param byte 2
* . . .
* . . .
* . . .
*
* The parameters generally line up, with some exceptions. Data
* overlaps parameters in DOS, not in OS/2.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* Verify the drive number.
* Get the drive handle.
* Map the 2f call to VDHDevIOCtl and call it.
* Map the os/2 return code to a dos rc.
* Reset media if necessary, otherwise
* check for drive playing and update the rc.
*
* INPUT = reqhdr - flat address of dos request packet
* drive_number - of the CD-ROM (0=A, 1=B...)
*
* OUTPUT = void
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
VOID PRIVENTRY SendDeviceRequest ( register
struct
DosRh *reqhdr, /* flat address */
ULONG drive_number )
{
register
PCHAR control_block;
register
ULONG rc;
ULONG saveCD01area;
ULONG save_number_of_sectors;
ULONG save_volume_size;
F16PVOID save_transfer_area;
HFILE handle;
struct
CategoryCode ioctl;
PVOID parm_list;
PVOID data_area;
BOOL media_check_in_progress;
if ( drive_number < FirstDriveNumber ||
drive_number >= FirstDriveNumber + NumberOfDrives )
{
reqhdr->status = ERROR + DONE + ERROR_I24_BAD_UNIT;
return;
}
handle = GetDriveHandle ( drive_number );
if ( handle == NULL )
{
reqhdr->status = ERROR + DONE + ERROR_I24_NOT_READY;
return;
} /* error exit */
ParmLengthInOut = PARM_LENGTH_MAX; /* these are just dummies for */
DataLengthInOut = DATA_LENGTH_MAX; /* the VDHDevIOCtl call */
switch ( reqhdr->command )
{
case DOS_IOCTL_INPUT:
control_block = PFROMVADDR ( FP_SEG ((RH(3) reqhdr)->control_block),
FP_OFF ((RH(3) reqhdr)->control_block)
);
if ( *control_block == RADDR ) /* dos driver address */
{
rc = NO_ERROR;
* ((PULONG) (control_block + 1)) = (ULONG) DosDDHeader;
break;
} /* return address of device header*/
ioctl = IoctlInputCodes [*control_block];
if ( ioctl.code == MEDIA_CHANGED_EXCEPTION ) /* not in OS/2 */
{
media_check_in_progress = TRUE;
ioctl.code = RETURN_VOLUME_SIZE; /* generates the error */
save_volume_size = * ( (PULONG) ( control_block + 1 ) );
}
else
{
media_check_in_progress = FALSE;
}
parm_list = control_block - 3; /* "CD01" then param then */
/* data area in DOS */
if ( *control_block == LOCHEAD ||
*control_block == SECTSIZE ||
*control_block == TNOINFO )
{
data_area = control_block + 2; /* skip over a param */
}
else
{
data_area = control_block + 1; /* skip over control code */
}
saveCD01area = * ( (PULONG) ( control_block - 3 ) );
* ( (PULONG) ( control_block - 3 ) ) = CD01;
rc = VDHDevIOCtl ( handle,
ioctl.category,
ioctl.code,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
* ( (PULONG) ( control_block - 3 ) ) = saveCD01area;
if (( *control_block == SECTSIZE ) && ( rc == NO_ERROR )) /*@V113078*/
{ /*@V113078*/
if ( * (PCHAR) ( control_block + 1 ) == RAW_MODE ) /*@V113078*/
{ /*@V113078*/
*(PUSHORT) data_area = CDROM_LONG_SECTOR_SIZE; /*@V113078*/
} /*@V113078*/
} /*@V113078*/
if ( media_check_in_progress )
{
* ( (PULONG) ( control_block + 1 ) ) = save_volume_size;
if ( (rc & 0xFF) == ERROR_I24_UNCERTAIN_MEDIA )
* ( (PUCHAR) ( control_block + 1 ) ) = MEDIA_UNCERTAIN;
else
* ( (PUCHAR) ( control_block + 1 ) ) = MEDIA_NOT_CHANGED;
}
break;
case DOS_IOCTL_OUTPUT:
control_block = PFROMVADDR ( FP_SEG ((RH(3) reqhdr)->control_block),
FP_OFF ((RH(3) reqhdr)->control_block)
);
ioctl = IoctlOutputCodes [*control_block];
parm_list = control_block - 3; /* CD01 then param and */
data_area = control_block + 1; /* data which overlap */
saveCD01area = * ( (PULONG) ( control_block - 3 ) );
* ( (PULONG) ( control_block - 3 ) ) = CD01;
rc = VDHDevIOCtl ( handle,
ioctl.category,
ioctl.code,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
* ( (PULONG) ( control_block - 3 ) ) = saveCD01area;
break;
case DOS_READ_LONG: /* OS/2 read command (4) */
if ((RH(128) reqhdr)->read_mode == COOKED_MODE ) /*@V113078*/
{ /*@V113078*/
if ((RH(128) reqhdr)->address_mode != HSG_ADDRESS ) /*@V113078*/
{
rc = DEVIOCTL_ERROR + ERROR_I24_BAD_COMMAND;
break;
}
rc = VDHSeek ( handle,
(RH(128) reqhdr)->start_sector * CDROM_SECTOR_SIZE,
VDHSK_ABSOLUTE );
if ( rc == VDH_ERROR )
{
rc = VDHGetError ();
break;
}
rc = VDHRead ( handle,
PFROMVADDR (FP_SEG ((RH(128) reqhdr)->transfer_area),
FP_OFF ((RH(128) reqhdr)->transfer_area)
),
(ULONG) (RH(128) reqhdr)->transfer_count *
CDROM_SECTOR_SIZE
);
if ( rc == VDH_ERROR )
{
rc = VDHGetError ();
(RH(128) reqhdr)->transfer_count = 0;
}
else
{
rc = NO_ERROR;
}
}
else if ((RH(128) reqhdr)->read_mode == RAW_MODE ) /*@V113078*/
{ /*VVVVVVVV*/
ioctl.code = IOCD_READ_LONG;
ioctl.category = IOC_CDROM;
control_block = PFROMVADDR (FP_SEG ((RH(128) reqhdr)->transfer_area),
FP_OFF ((RH(128) reqhdr)->transfer_area));
parm_list = control_block; /* CD01 then param and */
data_area = control_block; /* data which overlap */
((PREADLONGPARMS)parm_list)->ID_code = CD01;
if ((RH(128) reqhdr)->address_mode == HSG_ADDRESS )
{
((PREADLONGPARMS)parm_list)->address_mode = HSG_ADDRESS;
}
else if ((RH(128) reqhdr)->address_mode == REDBOOK_ADDRESS )
{
((PREADLONGPARMS)parm_list)->address_mode = REDBOOK_ADDRESS;
}
else /* invalid addressing mode */
{
rc = DEVIOCTL_ERROR + ERROR_I24_BAD_COMMAND;
break;
}
((PREADLONGPARMS)parm_list)->transfer_count =
(ULONG) (RH(128) reqhdr)->transfer_count;
((PREADLONGPARMS)parm_list)->start_sector =
(RH(128) reqhdr)->start_sector;
((PREADLONGPARMS)parm_list)->reserved = 0;
((PREADLONGPARMS)parm_list)->interleave_size = 0;
((PREADLONGPARMS)parm_list)->interleave_skip_factor = 0;
rc = VDHDevIOCtl ( handle,
ioctl.category,
ioctl.code,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
}
else /* invalid read mode */
{
rc = DEVIOCTL_ERROR + ERROR_I24_BAD_COMMAND; /*AAAAAAAA*/
} /*@V113078*/
break;
case DOS_READ_LONG_PREFETCH: /* fall thru */
case DOS_SEEK:
control_block = (PCHAR) reqhdr;
parm_list = control_block + 9; /* CD01 then params */
data_area = 0;
save_transfer_area = (RH(131) reqhdr)->transfer_area;
* ( (PULONG) &(RH(131) reqhdr)->transfer_area ) =
(RH(131) reqhdr)->start_sector;
saveCD01area = * ( (PULONG) ( control_block + 9 ) );
* ( (PULONG) ( control_block + 9 ) ) = CD01;
rc = VDHDevIOCtl ( handle,
0x0080,
0x0050,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
* ( (PULONG) ( control_block + 9 ) ) = saveCD01area;
(RH(131) reqhdr)->transfer_area = save_transfer_area;
break;
case DOS_PLAY_AUDIO:
control_block = (PCHAR) reqhdr;
parm_list = control_block + 9; /* CD01 then params */
data_area = 0;
save_number_of_sectors = (RH(132) reqhdr)->number_of_sectors;
* ( (PULONG) &(RH(132) reqhdr)->number_of_sectors ) =
AddSectors ( (RH(132) reqhdr)->start_sector,
(RH(132) reqhdr)->number_of_sectors,
(RH(132) reqhdr)->address_mode
);
saveCD01area = * ( (PULONG) ( control_block + 9 ) );
* ( (PULONG) ( control_block + 9 ) ) = CD01;
rc = VDHDevIOCtl ( handle,
0x0081,
0x0050,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
* ( (PULONG) ( control_block + 9 ) ) = saveCD01area;
* ( (PULONG) &(RH(132) reqhdr)->number_of_sectors ) =
save_number_of_sectors;
break;
case DOS_STOP_AUDIO:
control_block = (PCHAR) reqhdr;
parm_list = control_block + 9; /* CD01 then params */
data_area = 0;
saveCD01area = * ( (PULONG) ( control_block + 9 ) );
* ( (PULONG) ( control_block + 9 ) ) = CD01;
rc = VDHDevIOCtl ( handle,
0x0081,
0x0051,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
* ( (PULONG) ( control_block + 9 ) ) = saveCD01area;
break;
case DOS_RESUME_AUDIO:
control_block = (PCHAR) reqhdr;
parm_list = control_block + 9; /* CD01 then params */
data_area = 0;
saveCD01area = * ( (PULONG) ( control_block + 9 ) );
* ( (PULONG) ( control_block + 9 ) ) = CD01;
rc = VDHDevIOCtl ( handle,
0x0081,
0x0052,
parm_list,
PARM_LENGTH_MAX,
&ParmLengthInOut,
data_area,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
* ( (PULONG) ( control_block + 9 ) ) = saveCD01area;
break;
default:
switch ( reqhdr->command )
{
case DOS_DEVICE_OPEN:
ResetMedia ( drive_number );
case DOS_INPUT_FLUSH:
case DOS_DEVICE_CLOSE:
rc = NO_ERROR;
break;
default:
rc = DEVIOCTL_ERROR + ERROR_I24_BAD_COMMAND;
}
}
reqhdr->status = MapOS2toDosCode ( rc );
if ( (reqhdr->status & 0xFF) == ERROR_I24_WRONG_DISK ) //INV_DISK_CHANGE
ResetMedia ( drive_number );
else
reqhdr->status |= GetPlayStatus ( handle );
return;
}
/****************************************************************************
*
* FUNCTION NAME = ResetMedia
*
* DESCRIPTION = This function resets the uncertain media condition for the
* device. It is necessary because we are bypassing the file
* system with user-defined generic ioctls.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* Close and open the drive handle to reset media.
*
* INPUT = drive_number - of the CD-ROM (0=A, 1=B...)
*
* OUTPUT = void
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
VOID PRIVENTRY ResetMedia (ULONG drive_number)
{
register
ULONG rc;
VDHClose ( DriveHandle [ drive_number ] );
rc = VDHOpen ( GET_DRIVE_STRING ( drive_number ),
&FileHandle,
&ActionTaken,
FILESIZE,
FILEATTRIBUTE,
OPENFLAG,
OPENMODE,
EABUF );
if ( rc == VDH_FAILURE )
{
rc = VDHGetError (); /* for debugging */
FileHandle = NULL;
}
DriveHandle [ drive_number ] = FileHandle; /* NULL if error */
}
/****************************************************************************
*
* FUNCTION NAME = GetDriveHandle
*
* DESCRIPTION = This function maps the drive number to a possibly already
* opened drive handle. If the handle is not opened, one is
* opened and returned. If the handle is opened, a media check
* is performed to determine if the handle is still valid. If
* the handle is invalid, the handle is closed and a new handle
* is opened, stored, and returned. Performing a media check is
* faster than closing and openning the file handle especially
* for each MSCDEX api. The open is required to (re)mount the
* removable media volume. We only want to take the
* performance penalty of open/close when the media has truly
* changed.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* If the drive is not open,
* open drive and save handle
* else the drive is open
* perform media check
* if media changed
* close handle, open new handle and save it
* endif
* endif
* return handle
*
* INPUT = drive_number - of the CD-ROM (0=A, 1=B...)
*
* OUTPUT = DASD-open file handle (NULL == failure)
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
HFILE PRIVENTRY GetDriveHandle (ULONG drive_number)
{
register
ULONG rc;
FileHandle = DriveHandle [ drive_number ];
if ( FileHandle == NULL )
{
rc = VDHOpen ( GET_DRIVE_STRING ( drive_number ),
&FileHandle,
&ActionTaken,
FILESIZE,
FILEATTRIBUTE,
OPENFLAG,
OPENMODE,
EABUF );
if ( rc == VDH_FAILURE )
{
rc = VDHGetError (); /* for debugging */
FileHandle = NULL;
}
DriveHandle [ drive_number ] = FileHandle; /* NULL if error */
}
else
{
DataArea[0] = 0x0000;
DataLengthInOut = sizeof(USHORT);
ParmLengthInOut = 0x0000;
/* call CD-ROM IFS to see if media has changed */
rc = VDHFSCtl((PVOID)&DataArea,
(ULONG)DataLengthInOut,
(PVOID)&DataLengthInOut,
(PVOID)&ParmList,
(ULONG)ParmLengthInOut,
(PVOID)&ParmLengthInOut,
(ULONG)FSCTL_ARG_MEDIACHG,
(PSZ)NULL,
FileHandle,
FSCTL_HANDLE);
if ( rc == VDH_FAILURE ) {
rc = VDHGetError ();
}
if (DataArea[0] == ERROR_VOLUME_CHANGED)
{
ResetMedia ( drive_number );
FileHandle = DriveHandle [ drive_number ];
}
}
return FileHandle;
}
/****************************************************************************
*
* FUNCTION NAME = MapOS2toDosCode
*
* DESCRIPTION =
* This function converts the OS/2 return code to a DOS device
* driver status code.
*
* CONTEXT:
* VDM Task-time
*
* TYPES OF OS/2 CODES:
* 0000 = no error
* FFxx = device driver error code
* other = system error code
*
* PSEUDOCODE:
* Map the code according to its type.
*
* INPUT = OS/2 rc
*
* OUTPUT = DOS status code
*
* RETURN-NORMAL =
*
* RETURN-ERROR =
*
****************************************************************************/
USHORT PRIVENTRY MapOS2toDosCode (register ULONG rc)
{
register
ULONG dos_rc;
if (rc == 0)
{
dos_rc = DONE;
}
else
if (((USHORT)rc & 0xFF00) == DEVIOCTL_ERROR)
{
if (((USHORT)rc & 0xFF) == ERROR_I24_UNCERTAIN_MEDIA)
{
dos_rc = ERROR + DONE + ERROR_I24_WRONG_DISK; //INV_DISK_CHANGE
}
else
{
dos_rc = ERROR + DONE + ((USHORT) rc & 0xFF);
}
}
else
{ /* DosCall system error code */
if (rc >= ERROR_WRITE_PROTECT && rc <= ERROR_WRONG_DISK)
{
dos_rc = ERROR + DONE + (USHORT)rc - ERROR_WRITE_PROTECT;
}
else
{
dos_rc = ERROR + DONE + ERROR_I24_GEN_FAILURE;
}
}
if (dos_rc > ERROR + DONE + ERROR_I24_WRONG_DISK) //INV_DISK_CHANGE
{
dos_rc = ERROR + DONE + ERROR_I24_GEN_FAILURE;
}
return (USHORT)dos_rc;
}
/****************************************************************************
*
* FUNCTION NAME = GetPlayStatus
*
* DESCRIPTION = This function determines if the drive is currently playing
* audio.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* Make a device-status call to the OS/2 CD-ROM driver.
* If playing, set the busy bit.
*
* INPUT = DASD-open file handle
*
* OUTPUT = 0200h == playing
* 0000h == not playing
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
USHORT PRIVENTRY GetPlayStatus (HFILE handle)
{
register
ULONG rc;
ParmLengthInOut = PARM_LENGTH_MAX; /* these are just dummies for */
DataLengthInOut = DATA_LENGTH_MAX; /* the VDHDevIOCtl call */
*ParmList = CD01;
rc = VDHDevIOCtl ( handle,
0x0080,
0x0060, /* device status */
ParmList,
PARM_LENGTH_MAX,
&ParmLengthInOut,
DataArea,
DATA_LENGTH_MAX,
&DataLengthInOut );
if ( rc == VDH_FAILURE )
rc = VDHGetError ();
else
rc = NO_ERROR;
if ( rc == NO_ERROR && (*DataArea & DRIVE_PLAYING) )
return BUSY; /* busy bit == playing in DOS */
else
return 0;
}
/****************************************************************************
*
* FUNCTION NAME = HsgToRedbook
*
* DESCRIPTION = This function converts an HSG number-of-sectors to a Redbook
* (min:sec:frames) number-of-sectors.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* Convert long relative sector number to
* long 0:min:sec:frames.
* 75 frames per second
* 60 seconds per minute
* 1 frame == 1 HSG sector
*
* INPUT = HSG number_of_sectors
*
* OUTPUT = Redbook number_of_sectors
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
ULONG PRIVENTRY HsgToRedbook (register ULONG hsg_value)
{
UCHAR minutes;
UCHAR seconds;
UCHAR frames;
register
ULONG redbook;
redbook = 0;
redbook |= ( (hsg_value / (60 * 75)) << 16 ); /* minutes */
hsg_value %= (60 * 75); /* remaining frames */
redbook |= ( (hsg_value / 75) << 8 ); /* seconds */
redbook |= ( hsg_value % 75 ); /* frames */
return ( redbook );
}
/****************************************************************************
*
* FUNCTION NAME = AddSectors
*
* DESCRIPTION = This function adds two sector values, returning the sum. It
* is necessary because the OS/2 call requires the ending sector
* number, but the DOS parameter is number-of-sectors.
*
* CONTEXT:
* VDM Task-time
*
* PSEUDOCODE:
* If HSG (normal numbers), just add them.
* If RedBook (minutes, seconds, frames), convert the HSG
* value to redbook and then add each field separately,
* with carry.
*
* INPUT = start_sector
* number_of_sectors
* address_mode - HSG or RedBook
*
* OUTPUT = sum of the sectors
* 0 = invalid address mode
*
* RETURN-NORMAL =
* RETURN-ERROR =
*
****************************************************************************/
ULONG PRIVENTRY AddSectors (register ULONG start_sector,
register ULONG number_of_sectors,
ULONG address_mode)
{
register
ULONG value;
UCHAR carry;
UCHAR byte;
switch ( address_mode )
{
case HSG_ADDRESS:
value = start_sector + number_of_sectors;
break;
case REDBOOK_ADDRESS:
number_of_sectors = HsgToRedbook ( number_of_sectors );
value = 0;
byte = FRAMES ( start_sector ) + FRAMES ( number_of_sectors );
if ( byte > 74 )
{
byte -= 75;
carry = 1;
}
else
{
carry = 0;
}
value |= byte;
byte = SECONDS ( start_sector ) + SECONDS ( number_of_sectors ) +
carry;
if ( byte > 59 )
{
byte -= 60;
carry = 1;
}
else
{
carry = 0;
}
value |= byte << 8;
byte = MINUTES ( start_sector ) + MINUTES ( number_of_sectors ) +
carry;
value |= byte << 16;
break;
default:
value = 0;
}
return value;
}
#pragma END_SWAP_CODE