2017-05-30 03:38:38 +02:00
/*
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
*
* This file is part of the 86 Box distribution .
*
* Implementation of the CD - ROM host drive IOCTL interface for
* Windows using SCSI Passthrough Direct .
*
2018-03-15 22:57:24 +01:00
* Version : @ ( # ) cdrom_ioctl . c 1.0 .13 2018 / 03 / 15
2017-05-30 03:38:38 +02:00
*
2017-06-04 02:11:19 -04:00
* Authors : Sarah Walker , < http : //pcem-emulator.co.uk/>
2017-05-30 03:38:38 +02:00
* Miran Grca , < mgrca8 @ gmail . com >
2017-10-10 03:07:29 -04:00
*
2018-01-17 18:43:36 +01:00
* Copyright 2008 - 2018 Sarah Walker .
* Copyright 2016 - 2018 Miran Grca .
2017-05-30 03:38:38 +02:00
*/
2017-05-18 14:03:43 -04:00
# define WINVER 0x0600
# include <windows.h>
# include <io.h>
2017-09-25 04:31:20 -04:00
# include <ntddcdrm.h>
# include <ntddscsi.h>
# include <stdio.h>
# include <stdint.h>
# include <string.h>
# include <wchar.h>
2017-10-17 01:59:09 -04:00
# include "../86box.h"
2017-10-07 00:46:54 -04:00
# include "../device.h"
2017-09-04 01:52:29 -04:00
# include "../scsi/scsi.h"
2017-10-08 05:04:38 +02:00
# include "../cdrom/cdrom.h"
2017-10-10 03:07:29 -04:00
# include "../plat.h"
2017-09-04 01:52:29 -04:00
2017-05-18 14:03:43 -04:00
# define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f)
2017-09-04 01:52:29 -04:00
2017-11-24 02:23:00 -05:00
enum {
CD_STOPPED = 0 ,
CD_PLAYING ,
CD_PAUSED
} ;
2017-05-18 14:03:43 -04:00
2017-09-04 01:52:29 -04:00
2017-11-24 02:23:00 -05:00
typedef struct {
HANDLE hIOCTL ;
CDROM_TOC toc ;
int is_playing ;
2017-05-18 14:03:43 -04:00
} cdrom_ioctl_windows_t ;
2017-11-24 02:23:00 -05:00
2017-05-18 14:03:43 -04:00
cdrom_ioctl_windows_t cdrom_ioctl_windows [ CDROM_NUM ] ;
2018-02-02 00:14:17 +01:00
2017-11-24 02:23:00 -05:00
# ifdef ENABLE_CDROM_LOG
int cdrom_ioctl_do_log = ENABLE_CDROM_LOG ;
# endif
2017-05-18 14:03:43 -04:00
2017-11-24 02:23:00 -05:00
static CDROM ioctl_cdrom ;
2017-05-18 14:03:43 -04:00
2017-11-24 02:23:00 -05:00
static void
cdrom_ioctl_log ( const char * format , . . . )
2017-05-18 14:03:43 -04:00
{
# ifdef ENABLE_CDROM_LOG
2017-11-24 02:23:00 -05:00
if ( cdrom_ioctl_do_log ) {
va_list ap ;
va_start ( ap , format ) ;
vfprintf ( stdlog , format , ap ) ;
va_end ( ap ) ;
2017-12-04 11:59:26 -05:00
fflush ( stdlog ) ;
2017-11-24 02:23:00 -05:00
}
2017-05-18 14:03:43 -04:00
# endif
}
2017-06-01 01:47:54 +02:00
static int ioctl_hopen ( uint8_t id ) ;
2017-05-18 14:03:43 -04:00
void ioctl_audio_callback ( uint8_t id , int16_t * output , int len )
{
RAW_READ_INFO in ;
DWORD count ;
2017-05-19 00:25:16 +02:00
if ( ! cdrom_drives [ id ] . sound_on | | ( cdrom_ioctl [ id ] . cd_state ! = CD_PLAYING ) )
2017-05-18 14:03:43 -04:00
{
2017-05-19 00:25:16 +02:00
if ( cdrom_ioctl [ id ] . cd_state = = CD_PLAYING )
{
cdrom [ id ] . seek_pos + = ( len > > 11 ) ;
}
2017-05-18 14:03:43 -04:00
memset ( output , 0 , len * 2 ) ;
return ;
}
while ( cdrom_ioctl [ id ] . cd_buflen < len )
{
if ( cdrom [ id ] . seek_pos < cdrom_ioctl [ id ] . cd_end )
{
in . DiskOffset . LowPart = ( cdrom [ id ] . seek_pos - 150 ) * 2048 ;
in . DiskOffset . HighPart = 0 ;
in . SectorCount = 1 ;
in . TrackMode = CDDA ;
2018-03-15 22:57:24 +01:00
if ( ! DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_RAW_READ , & in , sizeof ( in ) , & ( cdrom [ id ] . cd_buffer [ cdrom_ioctl [ id ] . cd_buflen ] ) , 2352 , & count , NULL ) )
2017-05-18 14:03:43 -04:00
{
2018-03-15 22:57:24 +01:00
memset ( & ( cdrom [ id ] . cd_buffer [ cdrom_ioctl [ id ] . cd_buflen ] ) , 0 , ( BUF_SIZE - cdrom_ioctl [ id ] . cd_buflen ) * 2 ) ;
2017-06-01 01:47:54 +02:00
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
ioctl_close ( id ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
cdrom_ioctl [ id ] . cd_buflen = len ;
}
else
{
cdrom [ id ] . seek_pos + + ;
cdrom_ioctl [ id ] . cd_buflen + = ( 2352 / 2 ) ;
}
}
else
{
2018-03-15 22:57:24 +01:00
memset ( & ( cdrom [ id ] . cd_buffer [ cdrom_ioctl [ id ] . cd_buflen ] ) , 0 , ( BUF_SIZE - cdrom_ioctl [ id ] . cd_buflen ) * 2 ) ;
2017-06-01 01:47:54 +02:00
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
ioctl_close ( id ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
cdrom_ioctl [ id ] . cd_buflen = len ;
}
}
2018-03-15 22:57:24 +01:00
memcpy ( output , cdrom [ id ] . cd_buffer , len * 2 ) ;
memcpy ( & cdrom [ id ] . cd_buffer [ 0 ] , & ( cdrom [ id ] . cd_buffer [ len ] ) , ( BUF_SIZE - len ) * 2 ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_buflen - = len ;
}
void ioctl_audio_stop ( uint8_t id )
{
2017-06-01 01:47:54 +02:00
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
ioctl_close ( id ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
}
static int get_track_nr ( uint8_t id , uint32_t pos )
{
int c ;
int track = 0 ;
if ( ! cdrom_ioctl [ id ] . tocvalid )
{
return 0 ;
}
if ( cdrom_ioctl [ id ] . last_track_pos = = pos )
{
return cdrom_ioctl [ id ] . last_track_nr ;
}
for ( c = cdrom_ioctl_windows [ id ] . toc . FirstTrack ; c < cdrom_ioctl_windows [ id ] . toc . LastTrack ; c + + )
{
uint32_t track_address = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] +
( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] * 75 ) +
( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] * 75 * 60 ) ;
if ( track_address < = pos )
{
track = c ;
}
}
cdrom_ioctl [ id ] . last_track_pos = pos ;
cdrom_ioctl [ id ] . last_track_nr = track ;
return track ;
}
static uint32_t get_track_msf ( uint8_t id , uint32_t track_no )
{
int c ;
if ( ! cdrom_ioctl [ id ] . tocvalid )
{
return 0 ;
}
for ( c = cdrom_ioctl_windows [ id ] . toc . FirstTrack ; c < cdrom_ioctl_windows [ id ] . toc . LastTrack ; c + + )
{
if ( c = = track_no )
{
return cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] + ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] < < 8 ) + ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] < < 16 ) ;
}
}
return 0xffffffff ;
}
static void ioctl_playaudio ( uint8_t id , uint32_t pos , uint32_t len , int ismsf )
{
int m = 0 , s = 0 , f = 0 ;
uint32_t start_msf = 0 , end_msf = 0 ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
if ( ismsf = = 2 )
{
start_msf = get_track_msf ( id , pos ) ;
end_msf = get_track_msf ( id , len ) ;
if ( start_msf = = 0xffffffff )
{
return ;
}
if ( end_msf = = 0xffffffff )
{
return ;
}
m = ( start_msf > > 16 ) & 0xff ;
s = ( start_msf > > 8 ) & 0xff ;
f = start_msf & 0xff ;
pos = MSFtoLBA ( m , s , f ) ;
m = ( end_msf > > 16 ) & 0xff ;
s = ( end_msf > > 8 ) & 0xff ;
f = end_msf & 0xff ;
len = MSFtoLBA ( m , s , f ) ;
}
else if ( ismsf = = 1 )
{
m = ( pos > > 16 ) & 0xff ;
s = ( pos > > 8 ) & 0xff ;
f = pos & 0xff ;
if ( pos = = 0xffffff )
{
cdrom_ioctl_log ( " Playing from current position (MSF) \n " ) ;
pos = cdrom [ id ] . seek_pos ;
}
else
{
pos = MSFtoLBA ( m , s , f ) ;
}
m = ( len > > 16 ) & 0xff ;
s = ( len > > 8 ) & 0xff ;
f = len & 0xff ;
len = MSFtoLBA ( m , s , f ) ;
}
else if ( ismsf = = 0 )
{
if ( pos = = 0xffffffff )
{
cdrom_ioctl_log ( " Playing from current position \n " ) ;
pos = cdrom [ id ] . seek_pos ;
}
len + = pos ;
}
cdrom [ id ] . seek_pos = pos ;
cdrom_ioctl [ id ] . cd_end = len ;
if ( cdrom [ id ] . seek_pos < 150 )
{
/* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */
cdrom [ id ] . seek_pos = 150 ;
}
2017-06-01 01:47:54 +02:00
if ( ! cdrom_ioctl_windows [ id ] . is_playing )
{
ioctl_hopen ( id ) ;
cdrom_ioctl_windows [ id ] . is_playing = 1 ;
}
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_PLAYING ;
}
static void ioctl_pause ( uint8_t id )
{
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
if ( cdrom_ioctl [ id ] . cd_state = = CD_PLAYING )
{
cdrom_ioctl [ id ] . cd_state = CD_PAUSED ;
}
}
static void ioctl_resume ( uint8_t id )
{
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
if ( cdrom_ioctl [ id ] . cd_state = = CD_PAUSED )
{
cdrom_ioctl [ id ] . cd_state = CD_PLAYING ;
}
}
static void ioctl_stop ( uint8_t id )
{
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
2017-06-01 01:47:54 +02:00
if ( cdrom_ioctl_windows [ id ] . is_playing )
{
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
ioctl_close ( id ) ;
}
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
}
static int ioctl_ready ( uint8_t id )
{
unsigned long size ;
int temp ;
CDROM_TOC ltoc ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return 0 ;
}
2017-06-01 01:47:54 +02:00
if ( cdrom_ioctl_windows [ id ] . hIOCTL = = NULL )
{
ioctl_hopen ( id ) ;
temp = DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & ltoc , sizeof ( ltoc ) , & size , NULL ) ;
ioctl_close ( id ) ;
}
else
{
temp = DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & ltoc , sizeof ( ltoc ) , & size , NULL ) ;
}
2017-05-18 14:03:43 -04:00
if ( ! temp )
{
return 0 ;
}
if ( ( ltoc . TrackData [ ltoc . LastTrack ] . Address [ 1 ] ! = cdrom_ioctl_windows [ id ] . toc . TrackData [ cdrom_ioctl_windows [ id ] . toc . LastTrack ] . Address [ 1 ] ) | |
( ltoc . TrackData [ ltoc . LastTrack ] . Address [ 2 ] ! = cdrom_ioctl_windows [ id ] . toc . TrackData [ cdrom_ioctl_windows [ id ] . toc . LastTrack ] . Address [ 2 ] ) | |
( ltoc . TrackData [ ltoc . LastTrack ] . Address [ 3 ] ! = cdrom_ioctl_windows [ id ] . toc . TrackData [ cdrom_ioctl_windows [ id ] . toc . LastTrack ] . Address [ 3 ] ) | |
! cdrom_ioctl [ id ] . tocvalid | | ( cdrom_drives [ id ] . host_drive ! = cdrom_drives [ id ] . prev_host_drive ) )
{
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
if ( cdrom_drives [ id ] . host_drive ! = cdrom_drives [ id ] . prev_host_drive )
{
cdrom_drives [ id ] . prev_host_drive = cdrom_drives [ id ] . host_drive ;
}
return 1 ;
}
return 1 ;
}
static int ioctl_get_last_block ( uint8_t id , unsigned char starttrack , int msf , int maxlen , int single )
{
unsigned long size ;
int c , d = 0 ;
CDROM_TOC lbtoc ;
int lb = 0 ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return 0 ;
}
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & lbtoc , sizeof ( lbtoc ) , & size , NULL ) ;
ioctl_close ( id ) ;
cdrom_ioctl [ id ] . tocvalid = 1 ;
for ( c = d ; c < = lbtoc . LastTrack ; c + + )
{
uint32_t address ;
address = MSFtoLBA ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] ) ;
if ( address > lb )
{
lb = address ;
}
}
return lb ;
}
2017-06-01 01:47:54 +02:00
static void ioctl_read_capacity ( uint8_t id , uint8_t * b ) ;
2017-05-18 14:03:43 -04:00
static int ioctl_medium_changed ( uint8_t id )
{
unsigned long size ;
int temp ;
CDROM_TOC ltoc ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return 0 ; /* This will be handled by the not ready handler instead. */
}
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
temp = DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & ltoc , sizeof ( ltoc ) , & size , NULL ) ;
ioctl_close ( id ) ;
if ( ! temp )
{
return 0 ; /* Drive empty, a not ready handler matter, not disc change. */
}
if ( ! cdrom_ioctl [ id ] . tocvalid | | ( cdrom_drives [ id ] . host_drive ! = cdrom_drives [ id ] . prev_host_drive ) )
{
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
cdrom_ioctl_windows [ id ] . toc = ltoc ;
cdrom_ioctl [ id ] . tocvalid = 1 ;
if ( cdrom_drives [ id ] . host_drive ! = cdrom_drives [ id ] . prev_host_drive )
{
cdrom_drives [ id ] . prev_host_drive = cdrom_drives [ id ] . host_drive ;
}
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
cdrom_ioctl [ id ] . capacity_read = 0 ; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */
ioctl_read_capacity ( id , NULL ) ;
ioctl_close ( id ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cdrom_capacity = ioctl_get_last_block ( id , 0 , 0 , 4096 , 0 ) ;
return 1 ;
}
else
{
if ( ( ltoc . TrackData [ ltoc . LastTrack ] . Address [ 1 ] ! = cdrom_ioctl_windows [ id ] . toc . TrackData [ cdrom_ioctl_windows [ id ] . toc . LastTrack ] . Address [ 1 ] ) | |
( ltoc . TrackData [ ltoc . LastTrack ] . Address [ 2 ] ! = cdrom_ioctl_windows [ id ] . toc . TrackData [ cdrom_ioctl_windows [ id ] . toc . LastTrack ] . Address [ 2 ] ) | |
( ltoc . TrackData [ ltoc . LastTrack ] . Address [ 3 ] ! = cdrom_ioctl_windows [ id ] . toc . TrackData [ cdrom_ioctl_windows [ id ] . toc . LastTrack ] . Address [ 3 ] ) )
{
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
cdrom_ioctl_log ( " Setting TOC... \n " ) ;
cdrom_ioctl_windows [ id ] . toc = ltoc ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
cdrom_ioctl [ id ] . capacity_read = 0 ; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */
ioctl_read_capacity ( id , NULL ) ;
ioctl_close ( id ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cdrom_capacity = ioctl_get_last_block ( id , 0 , 0 , 4096 , 0 ) ;
return 1 ; /* TOC mismatches. */
}
}
return 0 ; /* None of the above, return 0. */
}
static uint8_t ioctl_getcurrentsubchannel ( uint8_t id , uint8_t * b , int msf )
{
CDROM_SUB_Q_DATA_FORMAT insub ;
SUB_Q_CHANNEL_DATA sub ;
unsigned long size ;
int pos = 0 , track ;
uint32_t cdpos , track_address , dat ;
if ( ! cdrom_drives [ id ] . host_drive ) return 0 ;
cdpos = cdrom [ id ] . seek_pos ;
if ( cdrom_ioctl [ id ] . last_subchannel_pos = = cdpos )
{
memcpy ( & insub , cdrom_ioctl [ id ] . sub_q_data_format , sizeof ( insub ) ) ;
memcpy ( & sub , cdrom_ioctl [ id ] . sub_q_channel_data , sizeof ( sub ) ) ;
}
else
{
insub . Format = IOCTL_CDROM_CURRENT_POSITION ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_Q_CHANNEL , & insub , sizeof ( insub ) , & sub , sizeof ( sub ) , & size , NULL ) ;
ioctl_close ( id ) ;
memset ( cdrom_ioctl [ id ] . sub_q_data_format , 0 , 16 ) ;
memcpy ( cdrom_ioctl [ id ] . sub_q_data_format , & insub , sizeof ( insub ) ) ;
memset ( cdrom_ioctl [ id ] . sub_q_channel_data , 0 , 256 ) ;
memcpy ( cdrom_ioctl [ id ] . sub_q_channel_data , & sub , sizeof ( sub ) ) ;
cdrom_ioctl [ id ] . last_subchannel_pos = cdpos ;
}
if ( cdrom_ioctl [ id ] . cd_state = = CD_PLAYING | | cdrom_ioctl [ id ] . cd_state = = CD_PAUSED )
{
track = get_track_nr ( id , cdpos ) ;
track_address = cdrom_ioctl_windows [ id ] . toc . TrackData [ track ] . Address [ 3 ] + ( cdrom_ioctl_windows [ id ] . toc . TrackData [ track ] . Address [ 2 ] * 75 ) + ( cdrom_ioctl_windows [ id ] . toc . TrackData [ track ] . Address [ 1 ] * 75 * 60 ) ;
cdrom_ioctl_log ( " cdpos = %i, track = %i, track_address = %i \n " , cdpos , track , track_address ) ;
b [ pos + + ] = sub . CurrentPosition . Control ;
b [ pos + + ] = track + 1 ;
b [ pos + + ] = sub . CurrentPosition . IndexNumber ;
if ( msf )
{
2017-05-19 00:25:16 +02:00
dat = cdpos + 150 ;
2017-05-18 14:03:43 -04:00
b [ pos + 3 ] = ( uint8_t ) ( dat % 75 ) ; dat / = 75 ;
b [ pos + 2 ] = ( uint8_t ) ( dat % 60 ) ; dat / = 60 ;
b [ pos + 1 ] = ( uint8_t ) dat ;
b [ pos ] = 0 ;
pos + = 4 ;
2018-02-25 17:14:10 +01:00
dat = cdpos - track_address - 150 ;
2017-05-18 14:03:43 -04:00
b [ pos + 3 ] = ( uint8_t ) ( dat % 75 ) ; dat / = 75 ;
b [ pos + 2 ] = ( uint8_t ) ( dat % 60 ) ; dat / = 60 ;
b [ pos + 1 ] = ( uint8_t ) dat ;
b [ pos ] = 0 ;
pos + = 4 ;
}
else
{
b [ pos + + ] = ( cdpos > > 24 ) & 0xff ;
b [ pos + + ] = ( cdpos > > 16 ) & 0xff ;
b [ pos + + ] = ( cdpos > > 8 ) & 0xff ;
b [ pos + + ] = cdpos & 0xff ;
cdpos - = track_address ;
b [ pos + + ] = ( cdpos > > 24 ) & 0xff ;
b [ pos + + ] = ( cdpos > > 16 ) & 0xff ;
b [ pos + + ] = ( cdpos > > 8 ) & 0xff ;
b [ pos + + ] = cdpos & 0xff ;
}
if ( cdrom_ioctl [ id ] . cd_state = = CD_PLAYING ) return 0x11 ;
return 0x12 ;
}
b [ pos + + ] = sub . CurrentPosition . Control ;
b [ pos + + ] = sub . CurrentPosition . TrackNumber ;
b [ pos + + ] = sub . CurrentPosition . IndexNumber ;
cdrom_ioctl_log ( " cdpos = %i, track_address = %i \n " , MSFtoLBA ( sub . CurrentPosition . AbsoluteAddress [ 1 ] , sub . CurrentPosition . AbsoluteAddress [ 2 ] , sub . CurrentPosition . AbsoluteAddress [ 3 ] ) , MSFtoLBA ( sub . CurrentPosition . TrackRelativeAddress [ 1 ] , sub . CurrentPosition . TrackRelativeAddress [ 2 ] , sub . CurrentPosition . TrackRelativeAddress [ 3 ] ) ) ;
if ( msf )
{
int c ;
for ( c = 0 ; c < 4 ; c + + )
{
b [ pos + + ] = sub . CurrentPosition . AbsoluteAddress [ c ] ;
}
for ( c = 0 ; c < 4 ; c + + )
{
b [ pos + + ] = sub . CurrentPosition . TrackRelativeAddress [ c ] ;
}
}
else
{
uint32_t temp = MSFtoLBA ( sub . CurrentPosition . AbsoluteAddress [ 1 ] , sub . CurrentPosition . AbsoluteAddress [ 2 ] , sub . CurrentPosition . AbsoluteAddress [ 3 ] ) ;
b [ pos + + ] = temp > > 24 ;
b [ pos + + ] = temp > > 16 ;
b [ pos + + ] = temp > > 8 ;
b [ pos + + ] = temp ;
temp = MSFtoLBA ( sub . CurrentPosition . TrackRelativeAddress [ 1 ] , sub . CurrentPosition . TrackRelativeAddress [ 2 ] , sub . CurrentPosition . TrackRelativeAddress [ 3 ] ) ;
b [ pos + + ] = temp > > 24 ;
b [ pos + + ] = temp > > 16 ;
b [ pos + + ] = temp > > 8 ;
b [ pos + + ] = temp ;
}
return 0x13 ;
}
static void ioctl_eject ( uint8_t id )
{
unsigned long size ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
2017-06-01 01:47:54 +02:00
if ( cdrom_ioctl_windows [ id ] . is_playing )
{
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
ioctl_stop ( id ) ;
}
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_STORAGE_EJECT_MEDIA , NULL , 0 , NULL , 0 , & size , NULL ) ;
ioctl_close ( id ) ;
}
static void ioctl_load ( uint8_t id )
{
unsigned long size ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
2017-06-01 01:47:54 +02:00
if ( cdrom_ioctl_windows [ id ] . is_playing )
{
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
ioctl_stop ( id ) ;
}
2017-05-18 14:03:43 -04:00
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_STORAGE_LOAD_MEDIA , NULL , 0 , NULL , 0 , & size , NULL ) ;
2017-06-01 01:47:54 +02:00
cdrom_ioctl [ id ] . capacity_read = 0 ; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */
ioctl_read_capacity ( id , NULL ) ;
2017-05-18 14:03:43 -04:00
ioctl_close ( id ) ;
cdrom_ioctl [ id ] . cdrom_capacity = ioctl_get_last_block ( id , 0 , 0 , 4096 , 0 ) ;
}
2018-02-15 23:14:44 +01:00
static int ioctl_is_track_audio ( uint8_t id , uint32_t pos , int ismsf )
2017-05-18 14:03:43 -04:00
{
int c ;
int control = 0 ;
uint32_t track_address = 0 ;
if ( ! cdrom_ioctl [ id ] . tocvalid )
{
return 0 ;
}
2018-01-17 18:43:36 +01:00
for ( c = 0 ; cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . TrackNumber ! = 0xaa ; c + + )
2017-05-18 14:03:43 -04:00
{
2018-02-15 23:14:44 +01:00
if ( ismsf ) {
track_address = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] ;
track_address | = ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] < < 8 ) ;
track_address | = ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] < < 16 ) ;
} else {
track_address = MSFtoLBA ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] ) ;
track_address - = 150 ;
}
2017-05-18 14:03:43 -04:00
2018-01-17 18:43:36 +01:00
if ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . TrackNumber > = cdrom_ioctl_windows [ id ] . toc . FirstTrack & &
cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . TrackNumber < = cdrom_ioctl_windows [ id ] . toc . LastTrack & &
track_address < = pos )
2017-05-18 14:03:43 -04:00
control = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Control ;
}
if ( ( control & 0xd ) < = 1 )
return 1 ;
else
return 0 ;
}
/* 00, 08, 10, 18, 20, 28, 30, 38 */
int flags_to_size [ 5 ] [ 32 ] = { { 0 , 0 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 , /* 00-38 (CD-DA) */
2352 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 , /* 40-78 */
2352 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 , /* 80-B8 */
2352 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 , 2352 } , /* C0-F8 */
{ 0 , 0 , 2048 , 2336 , 4 , - 296 , 2052 , 2344 , /* 00-38 (Mode 1) */
8 , - 296 , 2048 , 2048 , 12 , - 296 , 2052 , 2052 , /* 40-78 */
- 296 , - 296 , - 296 , - 296 , 16 , - 296 , 2064 , 2344 , /* 80-B8 */
- 296 , - 296 , 2048 , 2048 , 24 , - 296 , 2064 , 2352 } , /* C0-F8 */
{ 0 , 0 , 2336 , 2336 , 4 , - 296 , 2340 , 2340 , /* 00-38 (Mode 2 non-XA) */
8 , - 296 , 2336 , 2336 , 12 , - 296 , 2340 , 2340 , /* 40-78 */
- 296 , - 296 , - 296 , - 296 , 16 , - 296 , 2352 , 2340 , /* 80-B8 */
- 296 , - 296 , 2336 , 2336 , 24 , - 296 , 2352 , 2352 } , /* C0-F8 */
{ 0 , 0 , 2048 , 2336 , 4 , - 296 , - 296 , - 296 , /* 00-38 (Mode 2 Form 1) */
8 , - 296 , 2056 , 2344 , 12 , - 296 , 2060 , 2340 , /* 40-78 */
- 296 , - 296 , - 296 , - 296 , 16 , - 296 , - 296 , - 296 , /* 80-B8 */
- 296 , - 296 , - 296 , - 296 , 24 , - 296 , 2072 , 2352 } , /* C0-F8 */
{ 0 , 0 , 2328 , 2328 , 4 , - 296 , - 296 , - 296 , /* 00-38 (Mode 2 Form 2) */
8 , - 296 , 2336 , 2336 , 12 , - 296 , 2340 , 2340 , /* 40-78 */
- 296 , - 296 , - 296 , - 296 , 16 , - 296 , - 296 , - 296 , /* 80-B8 */
- 296 , - 296 , - 296 , - 296 , 24 , - 296 , 2352 , 2352 } /* C0-F8 */
} ;
static int ioctl_get_sector_data_type ( uint8_t id , uint8_t b0 , uint8_t b1 , uint8_t b2 , uint8_t b3 , int ismsf ) ;
static void cdrom_illegal_mode ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK ;
cdrom_ascq = 0 ;
}
struct sptd_with_sense
{
SCSI_PASS_THROUGH s ;
ULONG Filler ;
UCHAR sense [ 32 ] ;
UCHAR data [ 65536 ] ;
} sptd ;
static int ioctl_get_block_length ( uint8_t id , const UCHAR * cdb , int number_of_blocks , int no_length_check )
{
2017-06-01 01:47:54 +02:00
int sector_type = 0 ;
int temp_len = 0 ;
2017-05-18 14:03:43 -04:00
2017-06-01 01:47:54 +02:00
if ( no_length_check )
2017-05-18 14:03:43 -04:00
{
switch ( cdb [ 0 ] )
{
2017-10-23 01:36:00 +02:00
case 0x25 : /* READ CAPACITY */
case 0x44 : /* READ HEADER */
2017-05-18 14:03:43 -04:00
return 8 ;
case 0x42 : /* READ SUBCHANNEL */
case 0x43 : /* READ TOC */
case 0x51 : /* READ DISC INFORMATION */
case 0x52 : /* READ TRACK INFORMATION */
case 0x5A : /* MODE SENSE (10) */
2018-02-02 00:14:17 +01:00
return ( ( ( uint32_t ) cdb [ 7 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 8 ] ) ;
2017-10-23 01:36:00 +02:00
case 0xAD : /* READ DVD STRUCTURE */
2018-02-02 00:14:17 +01:00
return ( ( ( uint32_t ) cdb [ 8 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 9 ] ) ;
2017-05-18 14:03:43 -04:00
default :
return 65534 ;
}
}
switch ( cdb [ 0 ] )
{
2017-10-23 01:36:00 +02:00
case 0x25 : /* READ CAPACITY */
case 0x44 : /* READ HEADER */
2017-05-18 14:03:43 -04:00
return 8 ;
case 0x42 : /* READ SUBCHANNEL */
case 0x43 : /* READ TOC */
case 0x51 : /* READ DISC INFORMATION */
case 0x52 : /* READ TRACK INFORMATION */
case 0x5A : /* MODE SENSE (10) */
2018-02-02 00:14:17 +01:00
return ( ( ( uint32_t ) cdb [ 7 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 8 ] ) ;
case 0xAD : /* READ DVD STRUCTURE */
return ( ( ( uint32_t ) cdb [ 8 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 9 ] ) ;
2017-05-18 14:03:43 -04:00
case 0x08 :
case 0x28 :
case 0xa8 :
/* READ (6), READ (10), READ (12) */
return 2048 * number_of_blocks ;
break ;
case 0xb9 :
sector_type = ( cdb [ 1 ] > > 2 ) & 7 ;
if ( sector_type = = 0 )
{
sector_type = ioctl_get_sector_data_type ( id , 0 , cdb [ 3 ] , cdb [ 4 ] , cdb [ 5 ] , 1 ) ;
if ( sector_type = = 0 )
{
cdrom_illegal_mode ( id ) ;
return - 1 ;
}
}
goto common_handler ;
case 0xbe :
/* READ CD MSF, READ CD */
sector_type = ( cdb [ 1 ] > > 2 ) & 7 ;
if ( sector_type = = 0 )
{
sector_type = ioctl_get_sector_data_type ( id , cdb [ 2 ] , cdb [ 3 ] , cdb [ 4 ] , cdb [ 5 ] , 0 ) ;
if ( sector_type = = 0 )
{
cdrom_illegal_mode ( id ) ;
return - 1 ;
}
}
common_handler :
temp_len = flags_to_size [ sector_type - 1 ] [ cdb [ 9 ] > > 3 ] ;
if ( ( cdb [ 9 ] & 6 ) = = 2 )
{
temp_len + = 294 ;
}
else if ( ( cdb [ 9 ] & 6 ) = = 4 )
{
temp_len + = 296 ;
}
if ( ( cdb [ 10 ] & 7 ) = = 1 )
{
temp_len + = 96 ;
}
else if ( ( cdb [ 10 ] & 7 ) = = 2 )
{
temp_len + = 16 ;
}
else if ( ( cdb [ 10 ] & 7 ) = = 4 )
{
temp_len + = 96 ;
}
if ( temp_len < = 0 )
{
cdrom_illegal_mode ( id ) ;
return - 1 ;
}
return temp_len * cdrom [ id ] . requested_blocks ;
break ;
default :
/* Other commands */
return 65534 ;
break ;
}
}
static int SCSICommand ( uint8_t id , const UCHAR * cdb , UCHAR * buf , uint32_t * len , int no_length_check )
{
DWORD ioctl_bytes ;
int ioctl_rv = 0 ;
SCSISense . SenseKey = 0 ;
SCSISense . Asc = 0 ;
SCSISense . Ascq = 0 ;
* len = 0 ;
memset ( & sptd , 0 , sizeof ( sptd ) ) ;
sptd . s . Length = sizeof ( SCSI_PASS_THROUGH ) ;
sptd . s . CdbLength = 12 ;
sptd . s . DataIn = SCSI_IOCTL_DATA_IN ;
sptd . s . TimeOutValue = 80 * 60 ;
sptd . s . DataTransferLength = ioctl_get_block_length ( id , cdb , cdrom_ioctl [ id ] . actual_requested_blocks , no_length_check ) ;
sptd . s . SenseInfoOffset = ( uintptr_t ) & sptd . sense - ( uintptr_t ) & sptd ;
sptd . s . SenseInfoLength = 32 ;
sptd . s . DataBufferOffset = ( uintptr_t ) & sptd . data - ( uintptr_t ) & sptd ;
memcpy ( sptd . s . Cdb , cdb , 12 ) ;
ioctl_rv = DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_SCSI_PASS_THROUGH , & sptd , sizeof ( sptd ) , & sptd , sizeof ( sptd ) , & ioctl_bytes , NULL ) ;
if ( sptd . s . SenseInfoLength )
{
cdrom_sense_key = sptd . sense [ 2 ] ;
cdrom_asc = sptd . sense [ 12 ] ;
cdrom_ascq = sptd . sense [ 13 ] ;
}
cdrom_ioctl_log ( " Transferred length: %i (command: %02X) \n " , sptd . s . DataTransferLength , cdb [ 0 ] ) ;
cdrom_ioctl_log ( " Sense length: %i (%02X %02X %02X %02X %02X) \n " , sptd . s . SenseInfoLength , sptd . sense [ 0 ] , sptd . sense [ 1 ] , sptd . sense [ 2 ] , sptd . sense [ 12 ] , sptd . sense [ 13 ] ) ;
cdrom_ioctl_log ( " IOCTL bytes: %i; SCSI status: %i, status: %i, LastError: %08X \n " , ioctl_bytes , sptd . s . ScsiStatus , ioctl_rv , GetLastError ( ) ) ;
cdrom_ioctl_log ( " DATA: %02X %02X %02X %02X %02X %02X \n " , sptd . data [ 0 ] , sptd . data [ 1 ] , sptd . data [ 2 ] , sptd . data [ 3 ] , sptd . data [ 4 ] , sptd . data [ 5 ] ) ;
cdrom_ioctl_log ( " %02X %02X %02X %02X %02X %02X \n " , sptd . data [ 6 ] , sptd . data [ 7 ] , sptd . data [ 8 ] , sptd . data [ 9 ] , sptd . data [ 10 ] , sptd . data [ 11 ] ) ;
cdrom_ioctl_log ( " %02X %02X %02X %02X %02X %02X \n " , sptd . data [ 12 ] , sptd . data [ 13 ] , sptd . data [ 14 ] , sptd . data [ 15 ] , sptd . data [ 16 ] , sptd . data [ 17 ] ) ;
cdrom_ioctl_log ( " SENSE: %02X %02X %02X %02X %02X %02X \n " , sptd . sense [ 0 ] , sptd . sense [ 1 ] , sptd . sense [ 2 ] , sptd . sense [ 3 ] , sptd . sense [ 4 ] , sptd . sense [ 5 ] ) ;
cdrom_ioctl_log ( " %02X %02X %02X %02X %02X %02X \n " , sptd . sense [ 6 ] , sptd . sense [ 7 ] , sptd . sense [ 8 ] , sptd . sense [ 9 ] , sptd . sense [ 10 ] , sptd . sense [ 11 ] ) ;
cdrom_ioctl_log ( " %02X %02X %02X %02X %02X %02X \n " , sptd . sense [ 12 ] , sptd . sense [ 13 ] , sptd . sense [ 14 ] , sptd . sense [ 15 ] , sptd . sense [ 16 ] , sptd . sense [ 17 ] ) ;
* len = sptd . s . DataTransferLength ;
if ( sptd . s . DataTransferLength ! = 0 )
{
memcpy ( buf , sptd . data , sptd . s . DataTransferLength ) ;
}
return ioctl_rv ;
}
static void ioctl_read_capacity ( uint8_t id , uint8_t * b )
{
uint32_t len = 0 ;
const UCHAR cdb [ ] = { 0x25 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
UCHAR buf [ 16 ] ;
2017-07-17 13:14:30 +02:00
if ( ! cdrom_ioctl [ id ] . capacity_read | | ( b = = NULL ) )
2017-05-18 14:03:43 -04:00
{
SCSICommand ( id , cdb , buf , & len , 1 ) ;
memcpy ( cdrom_ioctl [ id ] . rcbuf , buf , len ) ;
cdrom_ioctl [ id ] . capacity_read = 1 ;
}
else
{
memcpy ( b , cdrom_ioctl [ id ] . rcbuf , 16 ) ;
}
}
static int ioctl_media_type_id ( uint8_t id )
{
uint8_t old_sense [ 3 ] = { 0 , 0 , 0 } ;
UCHAR msbuf [ 28 ] ;
uint32_t len = 0 ;
int sense = 0 ;
const UCHAR cdb [ ] = { 0x5A , 0x00 , 0x2A , 0 , 0 , 0 , 0 , 0 , 28 , 0 , 0 , 0 } ;
old_sense [ 0 ] = cdrom_sense_key ;
old_sense [ 1 ] = cdrom_asc ;
old_sense [ 2 ] = cdrom_asc ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
SCSICommand ( id , cdb , msbuf , & len , 1 ) ;
ioctl_close ( id ) ;
sense = cdrom_sense_key ;
cdrom_sense_key = old_sense [ 0 ] ;
cdrom_asc = old_sense [ 1 ] ;
cdrom_asc = old_sense [ 2 ] ;
if ( sense = = 0 )
{
return msbuf [ 2 ] ;
}
else
{
return 3 ;
}
}
static uint32_t msf_to_lba32 ( int lba )
{
int m = ( lba > > 16 ) & 0xff ;
int s = ( lba > > 8 ) & 0xff ;
int f = lba & 0xff ;
return ( m * 60 * 75 ) + ( s * 75 ) + f ;
}
static int ioctl_get_type ( uint8_t id , UCHAR * cdb , UCHAR * buf )
{
int i = 0 ;
int ioctl_rv = 0 ;
uint32_t len = 0 ;
for ( i = 2 ; i < = 5 ; i + + )
{
cdb [ 1 ] = i < < 2 ;
ioctl_rv = SCSICommand ( id , cdb , buf , & len , 1 ) ; /* Bypass length check so we don't risk calling this again and getting stuck in an endless up. */
if ( ioctl_rv )
{
return i ;
}
}
return 0 ;
}
static int ioctl_sector_data_type ( uint8_t id , int sector , int ismsf )
{
int ioctl_rv = 0 ;
UCHAR cdb_lba [ ] = { 0xBE , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0x10 , 0 , 0 } ;
UCHAR cdb_msf [ ] = { 0xB9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 , 0 , 0 } ;
UCHAR buf [ 2352 ] ;
cdb_lba [ 2 ] = ( sector > > 24 ) ;
cdb_lba [ 3 ] = ( ( sector > > 16 ) & 0xff ) ;
cdb_lba [ 4 ] = ( ( sector > > 8 ) & 0xff ) ;
cdb_lba [ 5 ] = ( sector & 0xff ) ;
cdb_msf [ 3 ] = cdb_msf [ 6 ] = ( ( sector > > 16 ) & 0xff ) ;
cdb_msf [ 4 ] = cdb_msf [ 7 ] = ( ( sector > > 8 ) & 0xff ) ;
cdb_msf [ 5 ] = cdb_msf [ 8 ] = ( sector & 0xff ) ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
if ( ioctl_is_track_audio ( id , sector , ismsf ) )
{
return 1 ;
}
if ( ismsf )
{
ioctl_rv = ioctl_get_type ( id , cdb_msf , buf ) ;
}
else
{
ioctl_rv = ioctl_get_type ( id , cdb_lba , buf ) ;
}
if ( ioctl_rv )
{
ioctl_close ( id ) ;
return ioctl_rv ;
}
if ( ismsf )
{
sector = msf_to_lba32 ( sector ) ;
if ( sector < 150 )
{
ioctl_close ( id ) ;
return 0 ;
}
sector - = 150 ;
ioctl_rv = ioctl_get_type ( id , ( UCHAR * ) cdb_lba , buf ) ;
}
ioctl_close ( id ) ;
return ioctl_rv ;
}
static int ioctl_get_sector_data_type ( uint8_t id , uint8_t b0 , uint8_t b1 , uint8_t b2 , uint8_t b3 , int ismsf )
{
int sector = b3 ;
sector | = ( ( uint32_t ) b2 ) < < 8 ;
sector | = ( ( uint32_t ) b1 ) < < 16 ;
sector | = ( ( uint32_t ) b0 ) < < 24 ;
return ioctl_sector_data_type ( id , sector , ismsf ) ;
}
static void ioctl_validate_toc ( uint8_t id )
{
unsigned long size ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return ;
}
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl_log ( " Validating TOC... \n " ) ;
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & cdrom_ioctl_windows [ id ] . toc , sizeof ( cdrom_ioctl_windows [ id ] . toc ) , & size , NULL ) ;
ioctl_close ( id ) ;
cdrom_ioctl [ id ] . tocvalid = 1 ;
}
UCHAR buf [ 262144 ] ;
static int ioctl_pass_through ( uint8_t id , uint8_t * in_cdb , uint8_t * b , uint32_t * len )
{
const UCHAR cdb [ 12 ] ;
int ret = 0 ;
2017-10-23 01:36:00 +02:00
2017-05-18 14:03:43 -04:00
int temp_block_length = 0 ;
int buffer_pos = 0 ;
uint32_t temp_len = 0 ;
2017-10-23 01:36:00 +02:00
int i = 0 ;
2017-05-18 14:03:43 -04:00
if ( in_cdb [ 0 ] = = 0x43 )
{
/* This is a read TOC, so we have to validate the TOC to make the rest of the emulator happy. */
ioctl_validate_toc ( id ) ;
}
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
memcpy ( ( void * ) cdb , in_cdb , 12 ) ;
2017-10-23 01:36:00 +02:00
temp_len = 0 ;
temp_block_length = ioctl_get_block_length ( id , cdb , cdrom [ id ] . requested_blocks , 0 ) ;
if ( temp_block_length ! = - 1 ) {
cdrom_ioctl [ id ] . actual_requested_blocks = 1 ;
if ( ( cdb [ 0 ] = = 0x08 ) | | ( cdb [ 0 ] = = 0x28 ) | | ( cdb [ 0 ] = = 0xA8 ) | | ( cdb [ 0 ] = = 0xB9 ) | | ( cdb [ 0 ] = = 0xBE ) ) {
2017-05-18 14:03:43 -04:00
buffer_pos = 0 ;
temp_len = 0 ;
2017-10-23 01:36:00 +02:00
for ( i = 0 ; i < cdrom [ id ] . requested_blocks ; i + + )
2017-05-18 14:03:43 -04:00
{
2017-10-23 01:36:00 +02:00
cdrom_ioctl_log ( " CD-ROM %i: ioctl_pass_through(): Transferring block... \n " , id , cdrom_ioctl [ id ] . actual_requested_blocks ) ;
cdrom_update_cdb ( ( uint8_t * ) cdb , cdrom [ id ] . sector_pos + i , 1 ) ;
ret = SCSICommand ( id , cdb , b + buffer_pos , & temp_len , 0 ) ;
buffer_pos + = temp_len ;
2017-05-18 14:03:43 -04:00
}
2017-10-23 01:36:00 +02:00
* len = buffer_pos ;
} else {
2017-05-18 14:03:43 -04:00
cdrom_ioctl_log ( " CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is smaller than 65534, transferring all at once... \n " , id , temp_block_length ) ;
2017-10-23 01:36:00 +02:00
ret = SCSICommand ( id , cdb , b , len , 0 ) ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl_log ( " CD-ROM %i: ioctl_pass_through(): Single transfer done \n " , id ) ;
}
}
2017-06-01 02:33:02 +02:00
cdrom_ioctl_log ( " IOCTL DATA: %02X %02X %02X %02X %02X %02X %02X %02X \n " , b [ 0 ] , b [ 1 ] , b [ 2 ] , b [ 3 ] , b [ 4 ] , b [ 5 ] , b [ 6 ] , b [ 7 ] ) ;
2017-05-18 14:03:43 -04:00
ioctl_close ( id ) ;
cdrom_ioctl_log ( " IOCTL Returned value: %i \n " , ret ) ;
return ret ;
}
2017-06-01 02:33:02 +02:00
static int ioctl_readtoc ( uint8_t id , unsigned char * b , unsigned char starttrack , int msf , int maxlen , int single )
{
int len = 4 ;
2017-06-16 06:44:11 +02:00
DWORD size ;
2017-06-01 02:33:02 +02:00
int c , d ;
uint32_t temp ;
uint32_t last_block ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return 0 ;
}
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
ioctl_hopen ( id ) ;
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & cdrom_ioctl_windows [ id ] . toc , sizeof ( cdrom_ioctl_windows [ id ] . toc ) , & size , NULL ) ;
ioctl_close ( id ) ;
cdrom_ioctl [ id ] . tocvalid = 1 ;
b [ 2 ] = cdrom_ioctl_windows [ id ] . toc . FirstTrack ;
b [ 3 ] = cdrom_ioctl_windows [ id ] . toc . LastTrack ;
d = 0 ;
for ( c = 0 ; c < = cdrom_ioctl_windows [ id ] . toc . LastTrack ; c + + )
{
if ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . TrackNumber > = starttrack )
{
d = c ;
break ;
}
}
last_block = 0 ;
for ( c = d ; c < = cdrom_ioctl_windows [ id ] . toc . LastTrack ; c + + )
{
uint32_t address ;
if ( ( len + 8 ) > maxlen ) break ;
b [ len + + ] = 0 ; /*Reserved*/
b [ len + + ] = ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Adr < < 4 ) | cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Control ;
b [ len + + ] = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . TrackNumber ;
b [ len + + ] = 0 ; /*Reserved*/
address = MSFtoLBA ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] ) ;
if ( address > last_block )
last_block = address ;
if ( msf )
{
b [ len + + ] = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 0 ] ;
b [ len + + ] = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] ;
b [ len + + ] = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] ;
b [ len + + ] = cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] ;
}
else
{
temp = MSFtoLBA ( cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 1 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 2 ] , cdrom_ioctl_windows [ id ] . toc . TrackData [ c ] . Address [ 3 ] ) - 150 ;
b [ len + + ] = temp > > 24 ;
b [ len + + ] = temp > > 16 ;
b [ len + + ] = temp > > 8 ;
b [ len + + ] = temp ;
}
if ( single ) break ;
}
b [ 0 ] = ( uint8_t ) ( ( ( len - 2 ) > > 8 ) & 0xff ) ;
b [ 1 ] = ( uint8_t ) ( ( len - 2 ) & 0xff ) ;
return len ;
}
static int ioctl_readtoc_session ( uint8_t id , unsigned char * b , int msf , int maxlen )
{
int len = 4 ;
int size ;
uint32_t temp ;
CDROM_READ_TOC_EX toc_ex ;
CDROM_TOC_SESSION_DATA toc ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return 0 ;
}
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
memset ( & toc_ex , 0 , sizeof ( toc_ex ) ) ;
memset ( & toc , 0 , sizeof ( toc ) ) ;
toc_ex . Format = CDROM_READ_TOC_EX_FORMAT_SESSION ;
toc_ex . Msf = msf ;
toc_ex . SessionTrack = 0 ;
ioctl_hopen ( id ) ;
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC_EX , & toc_ex , sizeof ( toc_ex ) , & toc , sizeof ( toc ) , ( PDWORD ) & size , NULL ) ;
ioctl_close ( id ) ;
b [ 2 ] = toc . FirstCompleteSession ;
b [ 3 ] = toc . LastCompleteSession ;
b [ len + + ] = 0 ; /*Reserved*/
b [ len + + ] = ( toc . TrackData [ 0 ] . Adr < < 4 ) | toc . TrackData [ 0 ] . Control ;
b [ len + + ] = toc . TrackData [ 0 ] . TrackNumber ;
b [ len + + ] = 0 ; /*Reserved*/
if ( msf )
{
b [ len + + ] = toc . TrackData [ 0 ] . Address [ 0 ] ;
b [ len + + ] = toc . TrackData [ 0 ] . Address [ 1 ] ;
b [ len + + ] = toc . TrackData [ 0 ] . Address [ 2 ] ;
b [ len + + ] = toc . TrackData [ 0 ] . Address [ 3 ] ;
}
else
{
temp = MSFtoLBA ( toc . TrackData [ 0 ] . Address [ 1 ] , toc . TrackData [ 0 ] . Address [ 2 ] , toc . TrackData [ 0 ] . Address [ 3 ] ) - 150 ;
b [ len + + ] = temp > > 24 ;
b [ len + + ] = temp > > 16 ;
b [ len + + ] = temp > > 8 ;
b [ len + + ] = temp ;
}
return len ;
}
static int ioctl_readtoc_raw ( uint8_t id , uint8_t * b , int maxlen )
{
int len = 4 ;
int size ;
int i ;
CDROM_READ_TOC_EX toc_ex ;
CDROM_TOC_FULL_TOC_DATA toc ;
if ( ! cdrom_drives [ id ] . host_drive )
{
return 0 ;
}
cdrom_ioctl [ id ] . cd_state = CD_STOPPED ;
memset ( & toc_ex , 0 , sizeof ( toc_ex ) ) ;
memset ( & toc , 0 , sizeof ( toc ) ) ;
toc_ex . Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC ;
toc_ex . Msf = 1 ;
toc_ex . SessionTrack = 0 ;
ioctl_hopen ( id ) ;
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC_EX , & toc_ex , sizeof ( toc_ex ) , & toc , sizeof ( toc ) , ( PDWORD ) & size , NULL ) ;
ioctl_close ( id ) ;
2017-08-23 02:49:12 +02:00
if ( maxlen > = 3 ) b [ 2 ] = toc . FirstCompleteSession ;
if ( maxlen > = 4 ) b [ 3 ] = toc . LastCompleteSession ;
if ( len > = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
size - = sizeof ( CDROM_TOC_FULL_TOC_DATA ) ;
size / = sizeof ( toc . Descriptors [ 0 ] ) ;
for ( i = 0 ; i < = size ; i + + )
{
b [ len + + ] = toc . Descriptors [ i ] . SessionNumber ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = ( toc . Descriptors [ i ] . Adr < < 4 ) | toc . Descriptors [ i ] . Control ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = 0 ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . Reserved1 ; /*Reserved*/
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . MsfExtra [ 0 ] ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . MsfExtra [ 1 ] ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . MsfExtra [ 2 ] ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . Zero ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . Msf [ 0 ] ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . Msf [ 1 ] ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
b [ len + + ] = toc . Descriptors [ i ] . Msf [ 2 ] ;
2017-08-23 02:49:12 +02:00
if ( len = = maxlen ) return len ;
2017-06-01 02:33:02 +02:00
}
return len ;
}
2017-05-18 14:03:43 -04:00
static uint32_t ioctl_size ( uint8_t id )
{
2017-07-17 13:14:30 +02:00
uint8_t capacity_buffer [ 16 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2017-05-18 14:03:43 -04:00
uint32_t capacity = 0 ;
ioctl_read_capacity ( id , capacity_buffer ) ;
capacity = ( ( uint32_t ) capacity_buffer [ 0 ] ) < < 24 ;
capacity | = ( ( uint32_t ) capacity_buffer [ 1 ] ) < < 16 ;
capacity | = ( ( uint32_t ) capacity_buffer [ 2 ] ) < < 8 ;
capacity | = ( uint32_t ) capacity_buffer [ 3 ] ;
return capacity + 1 ;
}
static int ioctl_status ( uint8_t id )
{
if ( ! ( ioctl_ready ( id ) ) & & ( cdrom_drives [ id ] . host_drive < = 0 ) )
{
return CD_STATUS_EMPTY ;
}
switch ( cdrom_ioctl [ id ] . cd_state )
{
case CD_PLAYING :
return CD_STATUS_PLAYING ;
case CD_PAUSED :
return CD_STATUS_PAUSED ;
case CD_STOPPED :
return CD_STATUS_STOPPED ;
default :
return CD_STATUS_EMPTY ;
}
}
void ioctl_reset ( uint8_t id )
{
CDROM_TOC ltoc ;
unsigned long size ;
if ( ! cdrom_drives [ id ] . host_drive )
{
cdrom_ioctl [ id ] . tocvalid = 0 ;
return ;
}
2017-06-01 01:47:54 +02:00
ioctl_hopen ( id ) ;
2017-05-18 14:03:43 -04:00
DeviceIoControl ( cdrom_ioctl_windows [ id ] . hIOCTL , IOCTL_CDROM_READ_TOC , NULL , 0 , & ltoc , sizeof ( ltoc ) , & size , NULL ) ;
ioctl_close ( id ) ;
cdrom_ioctl_windows [ id ] . toc = ltoc ;
cdrom_ioctl [ id ] . tocvalid = 1 ;
}
2017-06-01 01:47:54 +02:00
int ioctl_hopen ( uint8_t id )
{
if ( cdrom_ioctl_windows [ id ] . is_playing ) return 0 ;
cdrom_ioctl_windows [ id ] . hIOCTL = CreateFile ( cdrom_ioctl [ id ] . ioctl_path , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , 0 , NULL ) ;
return 0 ;
}
2017-05-18 14:03:43 -04:00
int ioctl_open ( uint8_t id , char d )
{
2017-06-01 01:47:54 +02:00
sprintf ( cdrom_ioctl [ id ] . ioctl_path , " \\ \\ . \\ %c: " , d ) ;
cdrom_ioctl [ id ] . tocvalid = 0 ;
2017-05-18 14:03:43 -04:00
cdrom_ioctl_windows [ id ] . hIOCTL = CreateFile ( cdrom_ioctl [ id ] . ioctl_path , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , 0 , NULL ) ;
cdrom_drives [ id ] . handler = & ioctl_cdrom ;
2017-06-01 01:47:54 +02:00
cdrom_ioctl [ id ] . ioctl_inited = 1 ;
cdrom_ioctl [ id ] . capacity_read = 0 ; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */
ioctl_read_capacity ( id , NULL ) ;
CloseHandle ( cdrom_ioctl_windows [ id ] . hIOCTL ) ;
cdrom_ioctl_windows [ id ] . hIOCTL = NULL ;
2017-05-18 14:03:43 -04:00
return 0 ;
}
void ioctl_close ( uint8_t id )
{
2017-06-01 01:47:54 +02:00
if ( cdrom_ioctl_windows [ id ] . is_playing ) return ;
2017-05-18 14:03:43 -04:00
if ( cdrom_ioctl_windows [ id ] . hIOCTL )
{
CloseHandle ( cdrom_ioctl_windows [ id ] . hIOCTL ) ;
cdrom_ioctl_windows [ id ] . hIOCTL = NULL ;
}
}
static void ioctl_exit ( uint8_t id )
{
2017-06-01 01:47:54 +02:00
cdrom_ioctl_windows [ id ] . is_playing = 0 ;
2017-05-18 14:03:43 -04:00
ioctl_stop ( id ) ;
cdrom_ioctl [ id ] . ioctl_inited = 0 ;
cdrom_ioctl [ id ] . tocvalid = 0 ;
}
static CDROM ioctl_cdrom =
{
ioctl_ready ,
ioctl_medium_changed ,
ioctl_media_type_id ,
ioctl_audio_callback ,
ioctl_audio_stop ,
2017-06-01 02:33:02 +02:00
ioctl_readtoc ,
ioctl_readtoc_session ,
ioctl_readtoc_raw ,
2017-05-18 14:03:43 -04:00
ioctl_getcurrentsubchannel ,
ioctl_pass_through ,
NULL ,
ioctl_playaudio ,
ioctl_load ,
ioctl_eject ,
ioctl_pause ,
ioctl_resume ,
ioctl_size ,
ioctl_status ,
ioctl_is_track_audio ,
ioctl_stop ,
ioctl_exit
} ;