2019-06-23 18:23:39 -04:00
/* Copyright (C) 2010-2019 The RetroArch team
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* The following license statement only applies to this file ( cdrom . c ) .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Permission is hereby granted , free of charge ,
* to any person obtaining a copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of the Software ,
* and to permit persons to whom the Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT .
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <cdrom/cdrom.h>
# include <libretro.h>
# include <stdio.h>
# include <string.h>
# include <compat/strl.h>
# include <retro_math.h>
2019-07-09 09:23:47 +02:00
# include <retro_timers.h>
2019-06-23 18:23:39 -04:00
# include <streams/file_stream.h>
# include <retro_endianness.h>
2019-06-25 19:34:29 -04:00
# include <retro_miscellaneous.h>
2019-06-26 21:45:00 -04:00
# include <vfs/vfs_implementation.h>
2019-07-03 14:19:16 -04:00
# include <lists/string_list.h>
# include <lists/dir_list.h>
# include <string/stdstring.h>
2019-07-21 12:06:01 -04:00
# include <memalign.h>
2019-06-23 18:23:39 -04:00
# include <math.h>
2019-07-09 09:23:47 +02:00
# ifdef _WIN32
# include <direct.h>
# else
2019-06-25 19:34:29 -04:00
# include <unistd.h>
2019-07-09 09:23:47 +02:00
# endif
2019-06-23 18:23:39 -04:00
2019-07-03 14:19:16 -04:00
# if defined(__linux__) && !defined(ANDROID)
2019-07-15 10:38:54 -04:00
# include <sys/ioctl.h>
2019-06-23 18:23:39 -04:00
# include <scsi/sg.h>
# endif
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-07-03 17:18:28 -04:00
# include <windows.h>
2019-06-26 21:45:00 -04:00
# include <winioctl.h>
# include <ntddscsi.h>
# endif
2019-07-02 00:12:00 -04:00
# define CDROM_CUE_TRACK_BYTES 107
2019-06-26 21:45:00 -04:00
# define CDROM_MAX_SENSE_BYTES 16
# define CDROM_MAX_RETRIES 10
2019-06-23 18:23:39 -04:00
typedef enum
{
DIRECTION_NONE ,
DIRECTION_IN ,
DIRECTION_OUT
} CDROM_CMD_Direction ;
2019-07-04 23:05:28 -04:00
void cdrom_lba_to_msf ( unsigned lba , unsigned char * min , unsigned char * sec , unsigned char * frame )
2019-06-23 18:23:39 -04:00
{
if ( ! min | | ! sec | | ! frame )
return ;
* frame = lba % 75 ;
lba / = 75 ;
* sec = lba % 60 ;
lba / = 60 ;
* min = lba ;
}
2019-07-04 23:05:28 -04:00
unsigned cdrom_msf_to_lba ( unsigned char min , unsigned char sec , unsigned char frame )
2019-06-23 18:23:39 -04:00
{
return ( min * 60 + sec ) * 75 + frame ;
}
void increment_msf ( unsigned char * min , unsigned char * sec , unsigned char * frame )
{
if ( ! min | | ! sec | | ! frame )
return ;
* min = ( * frame = = 74 ) ? ( * sec < 59 ? * min : * min + 1 ) : * min ;
* sec = ( * frame = = 74 ) ? ( * sec < 59 ? ( * sec + 1 ) : 0 ) : * sec ;
* frame = ( * frame < 74 ) ? ( * frame + 1 ) : 0 ;
}
2019-07-04 16:15:13 -04:00
static void cdrom_print_sense_data ( const unsigned char * sense , size_t len )
{
unsigned i ;
const char * sense_key_text = NULL ;
unsigned char key ;
unsigned char asc ;
unsigned char ascq ;
if ( len < 16 )
{
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Sense data buffer length too small. \n " ) ;
2019-07-04 16:15:13 -04:00
fflush ( stdout ) ;
return ;
}
key = sense [ 2 ] & 0xF ;
asc = sense [ 12 ] ;
ascq = sense [ 13 ] ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Sense Data: " ) ;
2019-07-04 16:15:13 -04:00
for ( i = 0 ; i < MIN ( len , 16 ) ; i + + )
{
printf ( " %02X " , sense [ i ] ) ;
}
printf ( " \n " ) ;
if ( sense [ 0 ] = = 0x70 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] CURRENT ERROR: \n " ) ;
2019-07-04 16:15:13 -04:00
if ( sense [ 0 ] = = 0x71 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] DEFERRED ERROR: \n " ) ;
2019-07-04 16:15:13 -04:00
switch ( key )
{
case 0 :
sense_key_text = " NO SENSE " ;
break ;
case 1 :
sense_key_text = " RECOVERED ERROR " ;
break ;
case 2 :
sense_key_text = " NOT READY " ;
break ;
case 3 :
sense_key_text = " MEDIUM ERROR " ;
break ;
case 4 :
sense_key_text = " HARDWARE ERROR " ;
break ;
case 5 :
sense_key_text = " ILLEGAL REQUEST " ;
break ;
case 6 :
sense_key_text = " UNIT ATTENTION " ;
break ;
case 7 :
sense_key_text = " DATA PROTECT " ;
break ;
case 8 :
sense_key_text = " BLANK CHECK " ;
break ;
case 9 :
sense_key_text = " VENDOR SPECIFIC " ;
break ;
case 10 :
sense_key_text = " COPY ABORTED " ;
break ;
case 11 :
sense_key_text = " ABORTED COMMAND " ;
break ;
case 13 :
sense_key_text = " VOLUME OVERFLOW " ;
break ;
case 14 :
sense_key_text = " MISCOMPARE " ;
break ;
}
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Sense Key: %02X (%s) \n " , key , sense_key_text ) ;
printf ( " [CDROM] ASC: %02X \n " , asc ) ;
printf ( " [CDROM] ASCQ: %02X \n " , ascq ) ;
2019-07-04 16:15:13 -04:00
switch ( key )
{
case 2 :
{
switch ( asc )
{
case 4 :
{
switch ( ascq )
{
case 1 :
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: LOGICAL UNIT IS IN PROCESS OF BECOMING READY \n " ) ;
2019-07-04 16:15:13 -04:00
break ;
default :
break ;
}
break ;
}
case 0x3a :
{
switch ( ascq )
{
case 0 :
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: MEDIUM NOT PRESENT \n " ) ;
2019-07-04 16:15:13 -04:00
break ;
case 3 :
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: MEDIUM NOT PRESENT - LOADABLE \n " ) ;
2019-07-04 16:15:13 -04:00
break ;
case 1 :
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: MEDIUM NOT PRESENT - TRAY CLOSED \n " ) ;
2019-07-04 16:15:13 -04:00
break ;
case 2 :
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: MEDIUM NOT PRESENT - TRAY OPEN \n " ) ;
2019-07-04 16:15:13 -04:00
break ;
default :
break ;
}
break ;
}
default :
break ;
}
}
2019-07-05 11:08:52 -04:00
case 3 :
{
if ( asc = = 0x11 & & ascq = = 0x5 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: L-EC UNCORRECTABLE ERROR \n " ) ;
2019-07-05 11:08:52 -04:00
break ;
}
case 5 :
{
if ( asc = = 0x20 & & ascq = = 0 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: INVALID COMMAND OPERATION CODE \n " ) ;
2019-07-05 11:08:52 -04:00
else if ( asc = = 0x24 & & ascq = = 0 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: INVALID FIELD IN CDB \n " ) ;
2019-07-05 11:08:52 -04:00
else if ( asc = = 0x26 & & ascq = = 0 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: INVALID FIELD IN PARAMETER LIST \n " ) ;
2019-07-05 11:08:52 -04:00
break ;
}
2019-07-04 16:15:13 -04:00
case 6 :
{
if ( asc = = 0x28 & & ascq = = 0 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Description: NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED \n " ) ;
2019-07-04 16:15:13 -04:00
break ;
}
default :
break ;
}
fflush ( stdout ) ;
}
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-07-21 12:06:01 -04:00
static int cdrom_send_command_win32 ( const libretro_vfs_implementation_file * stream , CDROM_CMD_Direction dir , void * buf , size_t len , unsigned char * cmd , size_t cmd_len , unsigned char * sense , size_t sense_len )
2019-06-23 18:23:39 -04:00
{
2019-06-26 21:45:00 -04:00
DWORD ioctl_bytes ;
BOOL ioctl_rv ;
2019-07-21 12:06:01 -04:00
# ifdef CDROM_DEBUG
clock_t t = clock ( ) ;
const char * extra = " " ;
static unsigned char last_min = 0 ;
static unsigned char last_sec = 0 ;
static unsigned char last_frame = 0 ;
unsigned lba_cur = cdrom_msf_to_lba ( last_min , last_sec , last_frame ) ;
unsigned lba_req = cdrom_msf_to_lba ( cmd [ 3 ] , cmd [ 4 ] , cmd [ 5 ] ) ;
# endif
2019-06-26 21:45:00 -04:00
struct sptd_with_sense
{
SCSI_PASS_THROUGH_DIRECT s ;
UCHAR sense [ 128 ] ;
} sptd ;
2019-06-23 18:23:39 -04:00
2019-06-26 21:45:00 -04:00
memset ( & sptd , 0 , sizeof ( sptd ) ) ;
2019-06-23 18:23:39 -04:00
2019-06-26 21:45:00 -04:00
sptd . s . Length = sizeof ( sptd . s ) ;
sptd . s . CdbLength = cmd_len ;
2019-06-25 02:51:51 -04:00
2019-06-26 21:45:00 -04:00
switch ( dir )
{
case DIRECTION_IN :
sptd . s . DataIn = SCSI_IOCTL_DATA_IN ;
break ;
case DIRECTION_OUT :
sptd . s . DataIn = SCSI_IOCTL_DATA_OUT ;
break ;
case DIRECTION_NONE :
default :
sptd . s . DataIn = SCSI_IOCTL_DATA_UNSPECIFIED ;
break ;
}
2019-07-05 23:45:48 -04:00
sptd . s . TimeOutValue = 5 ;
2019-06-26 21:45:00 -04:00
sptd . s . DataBuffer = buf ;
sptd . s . DataTransferLength = len ;
sptd . s . SenseInfoLength = sizeof ( sptd . sense ) ;
sptd . s . SenseInfoOffset = offsetof ( struct sptd_with_sense , sense ) ;
memcpy ( sptd . s . Cdb , cmd , cmd_len ) ;
2019-07-21 12:06:01 -04:00
ioctl_rv = DeviceIoControl ( stream - > fh , IOCTL_SCSI_PASS_THROUGH_DIRECT , & sptd ,
2019-06-26 21:45:00 -04:00
sizeof ( sptd ) , & sptd , sizeof ( sptd ) , & ioctl_bytes , NULL ) ;
2019-07-21 12:06:01 -04:00
# ifdef CDROM_DEBUG
if ( lba_req < lba_cur )
extra = " BACKWARDS SECTOR READ " ;
else if ( lba_req > lba_cur )
extra = " SKIPPED SECTOR READ " ;
if ( cmd [ 0 ] = = 0xB9 )
{
double time_taken = ( double ) ( ( ( clock ( ) - t ) * 1000 ) / CLOCKS_PER_SEC ) ;
printf ( " time taken %f ms for DT received length %ld of % " PRId64 " for %02d:%02d:%02d to %02d:%02d:%02d%s req %d cur %d cur_lba %d \n " , time_taken , sptd . s . DataTransferLength , len , cmd [ 3 ] , cmd [ 4 ] , cmd [ 5 ] , cmd [ 6 ] , cmd [ 7 ] , cmd [ 8 ] , extra , lba_req , lba_cur , stream - > cdrom . cur_lba ) ;
fflush ( stdout ) ;
}
last_min = cmd [ 3 ] ;
last_sec = cmd [ 4 ] ;
last_frame = cmd [ 5 ] ;
increment_msf ( & last_min , & last_sec , & last_frame ) ;
# endif
2019-07-04 00:21:41 -04:00
if ( ! ioctl_rv | | sptd . s . ScsiStatus ! = 0 )
2019-06-25 02:51:51 -04:00
return 1 ;
2019-06-26 21:45:00 -04:00
return 0 ;
}
# endif
2019-07-03 14:19:16 -04:00
# if defined(__linux__) && !defined(ANDROID)
2019-07-21 12:06:01 -04:00
static int cdrom_send_command_linux ( const libretro_vfs_implementation_file * stream , CDROM_CMD_Direction dir , void * buf , size_t len , unsigned char * cmd , size_t cmd_len , unsigned char * sense , size_t sense_len )
2019-06-26 21:45:00 -04:00
{
sg_io_hdr_t sgio = { 0 } ;
int rv ;
2019-06-23 18:23:39 -04:00
switch ( dir )
{
case DIRECTION_IN :
sgio . dxfer_direction = SG_DXFER_FROM_DEV ;
break ;
case DIRECTION_OUT :
sgio . dxfer_direction = SG_DXFER_TO_DEV ;
break ;
case DIRECTION_NONE :
default :
sgio . dxfer_direction = SG_DXFER_NONE ;
break ;
}
2019-06-26 21:51:40 -04:00
sgio . interface_id = ' S ' ;
2019-06-23 18:23:39 -04:00
sgio . cmd_len = cmd_len ;
sgio . cmdp = cmd ;
2019-06-26 21:51:40 -04:00
sgio . dxferp = buf ;
sgio . dxfer_len = len ;
2019-06-23 18:23:39 -04:00
sgio . sbp = sense ;
2019-06-26 21:45:00 -04:00
sgio . mx_sb_len = sense_len ;
2019-07-05 23:45:48 -04:00
sgio . timeout = 5000 ;
2019-06-26 21:45:00 -04:00
2019-07-21 12:06:01 -04:00
rv = ioctl ( fileno ( stream - > fp ) , SG_IO , & sgio ) ;
2019-06-26 21:45:00 -04:00
if ( rv = = - 1 | | sgio . info & SG_INFO_CHECK )
return 1 ;
return 0 ;
}
# endif
2019-07-21 12:06:01 -04:00
static int cdrom_send_command ( libretro_vfs_implementation_file * stream , CDROM_CMD_Direction dir , void * buf , size_t len , unsigned char * cmd , size_t cmd_len , size_t skip )
2019-06-26 21:45:00 -04:00
{
2019-07-21 12:06:01 -04:00
unsigned char * xfer_buf = NULL ;
unsigned char * xfer_buf_pos = xfer_buf ;
2019-06-26 21:45:00 -04:00
unsigned char sense [ CDROM_MAX_SENSE_BYTES ] = { 0 } ;
unsigned char retries_left = CDROM_MAX_RETRIES ;
2019-07-21 12:06:01 -04:00
int i , rv = 0 ;
int frames = 1 ;
2019-07-04 22:42:42 -04:00
size_t padded_req_bytes ;
2019-07-21 12:06:01 -04:00
size_t copied_bytes = 0 ;
bool read_cd = false ;
2019-06-26 21:45:00 -04:00
if ( ! cmd | | cmd_len = = 0 )
return 1 ;
2019-07-04 22:42:42 -04:00
if ( cmd [ 0 ] = = 0xBE | | cmd [ 0 ] = = 0xB9 )
2019-07-21 12:06:01 -04:00
{
frames = ceil ( ( len + skip ) / 2352.0 ) ;
padded_req_bytes = 2352 * frames ;
read_cd = true ;
/* these will be incremented below */
cmd [ 6 ] = cmd [ 3 ] ;
cmd [ 7 ] = cmd [ 4 ] ;
cmd [ 8 ] = cmd [ 5 ] ;
}
2019-07-04 22:42:42 -04:00
else
2019-07-21 12:06:01 -04:00
{
2019-07-04 22:42:42 -04:00
padded_req_bytes = len + skip ;
2019-07-21 12:06:01 -04:00
}
2019-07-04 22:42:42 -04:00
2019-07-21 12:06:01 -04:00
xfer_buf = ( unsigned char * ) memalign_alloc ( 4096 , padded_req_bytes ) ;
xfer_buf_pos = xfer_buf ;
2019-06-26 21:45:00 -04:00
if ( ! xfer_buf )
return 1 ;
2019-07-21 12:06:01 -04:00
memset ( xfer_buf , 0 , padded_req_bytes ) ;
2019-06-25 19:34:29 -04:00
# ifdef CDROM_DEBUG
2019-07-21 12:06:01 -04:00
printf ( " Number of frames to read: %d \n " , frames ) ;
fflush ( stdout ) ;
# endif
for ( i = 0 ; i < frames ; i + + )
2019-06-25 19:34:29 -04:00
{
2019-07-21 12:06:01 -04:00
size_t request_len = padded_req_bytes ;
size_t copy_len = request_len ;
bool cached_read = false ;
2019-06-25 19:34:29 -04:00
2019-07-21 12:06:01 -04:00
if ( read_cd )
2019-06-25 19:34:29 -04:00
{
2019-07-21 12:06:01 -04:00
unsigned lba_req = 0 ;
request_len = 2352 ;
copy_len = request_len ;
increment_msf ( & cmd [ 6 ] , & cmd [ 7 ] , & cmd [ 8 ] ) ;
if ( i > 0 )
{
skip = 0 ;
increment_msf ( & cmd [ 3 ] , & cmd [ 4 ] , & cmd [ 5 ] ) ;
}
else
{
if ( skip )
copy_len - = skip ;
}
if ( i = = frames - 1 )
{
copy_len = len - copied_bytes ;
}
lba_req = cdrom_msf_to_lba ( cmd [ 3 ] , cmd [ 4 ] , cmd [ 5 ] ) ;
if ( stream - > cdrom . last_frame_valid & & lba_req = = stream - > cdrom . last_frame_lba )
{
/* use cached frame */
cached_read = true ;
# ifdef CDROM_DEBUG
printf ( " [CDROM] Using cached frame \n " ) ;
fflush ( stdout ) ;
# endif
/* assumes request_len is always equal to the size of last_frame */
memcpy ( xfer_buf_pos , stream - > cdrom . last_frame , sizeof ( stream - > cdrom . last_frame ) ) ;
}
2019-06-25 19:34:29 -04:00
}
2019-07-21 12:06:01 -04:00
# ifdef CDROM_DEBUG
if ( ! cached_read )
{
unsigned j ;
2019-07-04 22:42:42 -04:00
2019-07-21 12:06:01 -04:00
printf ( " [CDROM] Send Command: " ) ;
for ( j = 0 ; j < cmd_len / sizeof ( * cmd ) ; j + + )
{
printf ( " %02X " , cmd [ j ] ) ;
}
if ( len )
printf ( " (buffer of size % " PRId64 " with skip bytes % " PRId64 " padded to % " PRId64 " ), frame %d \n " , len , skip , padded_req_bytes , i ) ;
else
printf ( " \n " ) ;
fflush ( stdout ) ;
}
2019-06-25 19:34:29 -04:00
# endif
2019-06-23 18:23:39 -04:00
2019-06-26 21:45:00 -04:00
retry :
2019-07-03 14:19:16 -04:00
# if defined(__linux__) && !defined(ANDROID)
2019-07-21 12:06:01 -04:00
if ( cached_read | | ! cdrom_send_command_linux ( stream , dir , xfer_buf_pos , request_len , cmd , cmd_len , sense , sizeof ( sense ) ) )
2019-06-26 21:45:00 -04:00
# else
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-07-21 12:06:01 -04:00
if ( cached_read | | ! cdrom_send_command_win32 ( stream , dir , xfer_buf_pos , request_len , cmd , cmd_len , sense , sizeof ( sense ) ) )
2019-06-26 21:45:00 -04:00
# endif
# endif
2019-06-25 02:51:51 -04:00
{
2019-07-21 12:06:01 -04:00
rv = 0 ;
2019-07-04 16:15:13 -04:00
2019-07-21 12:06:01 -04:00
if ( buf )
2019-07-03 17:18:28 -04:00
{
2019-07-21 12:06:01 -04:00
#if 0
printf ( " offsetting % " PRId64 " from buf, copying at xfer_buf offset % " PRId64 " , copying % " PRId64 " bytes \n " , copied_bytes , ( xfer_buf_pos + skip ) - xfer_buf , copy_len ) ;
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-07-21 12:06:01 -04:00
memcpy ( ( char * ) buf + copied_bytes , xfer_buf_pos + skip , copy_len ) ;
copied_bytes + = copy_len ;
2019-06-25 19:34:29 -04:00
2019-07-21 12:06:01 -04:00
if ( read_cd & & ! cached_read & & request_len > = 2352 )
{
unsigned frame_end = cdrom_msf_to_lba ( cmd [ 6 ] , cmd [ 7 ] , cmd [ 8 ] ) ;
/* cache the last received frame */
memcpy ( stream - > cdrom . last_frame , xfer_buf_pos , sizeof ( stream - > cdrom . last_frame ) ) ;
stream - > cdrom . last_frame_valid = true ;
/* the ending frame is never actually read, so what we really just read is the one right before that */
stream - > cdrom . last_frame_lba = frame_end - 1 ;
}
else
stream - > cdrom . last_frame_valid = false ;
#if 0
printf ( " Frame %d, adding % " PRId64 " to buf_pos, is now % " PRId64 " . skip is % " PRId64 " \n " , i , request_len , ( xfer_buf_pos + request_len ) - xfer_buf , skip ) ;
fflush ( stdout ) ;
# endif
xfer_buf_pos + = request_len ;
2019-07-03 17:18:28 -04:00
}
2019-06-25 02:51:51 -04:00
}
2019-07-21 12:06:01 -04:00
else
{
cdrom_print_sense_data ( sense , sizeof ( sense ) ) ;
/* INQUIRY/TEST/SENSE should never fail, don't retry. */
/* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
if ( cmd [ 0 ] ! = 0x0 & & cmd [ 0 ] ! = 0x12 & & cmd [ 0 ] ! = 0x5A & & ! ( cmd [ 0 ] = = 0x43 & & cmd [ 2 ] = = 0x4 ) )
{
unsigned char key = sense [ 2 ] & 0xF ;
switch ( key )
{
case 0 :
case 2 :
case 3 :
case 4 :
case 6 :
if ( retries_left )
{
# ifdef CDROM_DEBUG
printf ( " [CDROM] Read Retry... \n " ) ;
fflush ( stdout ) ;
# endif
retries_left - - ;
retro_sleep ( 1000 ) ;
goto retry ;
}
else
{
rv = 1 ;
# ifdef CDROM_DEBUG
printf ( " [CDROM] Read retries failed, giving up. \n " ) ;
fflush ( stdout ) ;
# endif
}
break ;
default :
break ;
}
}
2019-06-23 18:23:39 -04:00
2019-07-21 12:06:01 -04:00
rv = 1 ;
}
2019-06-25 02:51:51 -04:00
}
if ( xfer_buf )
2019-07-21 12:06:01 -04:00
memalign_free ( xfer_buf ) ;
2019-06-23 18:23:39 -04:00
2019-06-26 21:45:00 -04:00
return rv ;
2019-06-23 18:23:39 -04:00
}
2019-07-04 00:21:41 -04:00
static const char * get_profile ( unsigned short profile )
{
switch ( profile )
{
case 2 :
return " Removable disk " ;
break ;
case 8 :
return " CD-ROM " ;
break ;
case 9 :
return " CD-R " ;
break ;
case 0xA :
return " CD-RW " ;
break ;
case 0x10 :
return " DVD-ROM " ;
break ;
case 0x11 :
return " DVD-R Sequential Recording " ;
break ;
case 0x12 :
return " DVD-RAM " ;
break ;
case 0x13 :
return " DVD-RW Restricted Overwrite " ;
break ;
case 0x14 :
return " DVD-RW Sequential recording " ;
break ;
case 0x15 :
return " DVD-R Dual Layer Sequential Recording " ;
break ;
case 0x16 :
return " DVD-R Dual Layer Jump Recording " ;
break ;
case 0x17 :
return " DVD-RW Dual Layer " ;
break ;
case 0x1A :
return " DVD+RW " ;
break ;
case 0x1B :
return " DVD+R " ;
break ;
case 0x2A :
return " DVD+RW Dual Layer " ;
break ;
case 0x2B :
return " DVD+R Dual Layer " ;
break ;
case 0x40 :
return " BD-ROM " ;
break ;
case 0x41 :
return " BD-R SRM " ;
break ;
case 0x42 :
return " BD-R RRM " ;
break ;
case 0x43 :
return " BD-RE " ;
break ;
case 0x50 :
return " HD DVD-ROM " ;
break ;
case 0x51 :
return " HD DVD-R " ;
break ;
case 0x52 :
return " HD DVD-RAM " ;
break ;
case 0x53 :
return " HD DVD-RW " ;
break ;
case 0x58 :
return " HD DVD-R Dual Layer " ;
break ;
case 0x5A :
return " HD DVD-RW Dual Layer " ;
break ;
default :
break ;
}
return " Unknown " ;
}
2019-07-21 12:06:01 -04:00
int cdrom_get_sense ( libretro_vfs_implementation_file * stream , unsigned char * sense , size_t len )
2019-07-04 16:15:13 -04:00
{
unsigned char cdb [ ] = { 0x3 , 0 , 0 , 0 , 0xFC , 0 } ;
unsigned char buf [ 0xFC ] = { 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] get sense data status code %d \n " , rv ) ;
2019-07-04 16:15:13 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return 1 ;
cdrom_print_sense_data ( buf , sizeof ( buf ) ) ;
return 0 ;
}
2019-07-21 12:06:01 -04:00
void cdrom_get_current_config_random_readable ( libretro_vfs_implementation_file * stream )
2019-07-04 00:21:41 -04:00
{
unsigned char cdb [ ] = { 0x46 , 0x2 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0x14 , 0 } ;
unsigned char buf [ 0x14 ] = { 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
int i ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] get current config random readable status code %d \n " , rv ) ;
2019-07-04 00:21:41 -04:00
if ( rv )
return ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Feature Header: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 8 ; i + + )
{
printf ( " %02X " , buf [ i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Random Readable Feature Descriptor: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 12 ; i + + )
{
printf ( " %02X " , buf [ 8 + i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Supported commands: READ CAPACITY, READ (10) \n " ) ;
2019-07-04 00:21:41 -04:00
}
2019-07-21 12:06:01 -04:00
void cdrom_get_current_config_multiread ( libretro_vfs_implementation_file * stream )
2019-07-04 00:21:41 -04:00
{
unsigned char cdb [ ] = { 0x46 , 0x2 , 0 , 0x1D , 0 , 0 , 0 , 0 , 0xC , 0 } ;
unsigned char buf [ 0xC ] = { 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
int i ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] get current config multi-read status code %d \n " , rv ) ;
2019-07-04 00:21:41 -04:00
if ( rv )
return ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Feature Header: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 8 ; i + + )
{
printf ( " %02X " , buf [ i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Multi-Read Feature Descriptor: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 4 ; i + + )
{
printf ( " %02X " , buf [ 8 + i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Supported commands: READ (10), READ CD, READ DISC INFORMATION, READ TRACK INFORMATION \n " ) ;
2019-07-04 00:21:41 -04:00
}
2019-07-21 12:06:01 -04:00
void cdrom_get_current_config_cdread ( libretro_vfs_implementation_file * stream )
2019-07-04 00:21:41 -04:00
{
unsigned char cdb [ ] = { 0x46 , 0x2 , 0 , 0x1E , 0 , 0 , 0 , 0 , 0x10 , 0 } ;
unsigned char buf [ 0x10 ] = { 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
int i ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] get current config cd read status code %d \n " , rv ) ;
2019-07-04 00:21:41 -04:00
if ( rv )
return ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Feature Header: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 8 ; i + + )
{
printf ( " %02X " , buf [ i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] CD Read Feature Descriptor: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 8 ; i + + )
{
printf ( " %02X " , buf [ 8 + i ] ) ;
}
if ( buf [ 8 + 2 ] & 1 )
printf ( " (current) \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Supported commands: READ CD, READ CD MSF, READ TOC/PMA/ATIP \n " ) ;
2019-07-04 00:21:41 -04:00
}
2019-07-21 12:06:01 -04:00
void cdrom_get_current_config_profiles ( libretro_vfs_implementation_file * stream )
2019-07-04 00:21:41 -04:00
{
unsigned char cdb [ ] = { 0x46 , 0x2 , 0 , 0x0 , 0 , 0 , 0 , 0xFF , 0xFA , 0 } ;
unsigned char buf [ 0xFFFA ] = { 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
int i ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] get current config profiles status code %d \n " , rv ) ;
2019-07-04 00:21:41 -04:00
if ( rv )
return ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Feature Header: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 8 ; i + + )
{
printf ( " %02X " , buf [ i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Profile List Descriptor: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 4 ; i + + )
{
printf ( " %02X " , buf [ 8 + i ] ) ;
}
printf ( " \n " ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Number of profiles: %u \n " , buf [ 8 + 3 ] / 4 ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < buf [ 8 + 3 ] / 4 ; i + + )
{
unsigned short profile = ( buf [ 8 + ( 4 * ( i + 1 ) ) ] < < 8 ) | buf [ 8 + ( 4 * ( i + 1 ) ) + 1 ] ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Profile Number: %04X (%s) " , profile , get_profile ( profile ) ) ;
2019-07-04 00:21:41 -04:00
if ( buf [ 8 + ( 4 * ( i + 1 ) ) + 2 ] & 1 )
printf ( " (current) \n " ) ;
else
printf ( " \n " ) ;
}
}
2019-07-21 12:06:01 -04:00
void cdrom_get_current_config_core ( libretro_vfs_implementation_file * stream )
2019-07-04 00:21:41 -04:00
{
unsigned char cdb [ ] = { 0x46 , 0x2 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0x14 , 0 } ;
unsigned char buf [ 20 ] = { 0 } ;
unsigned intf_std = 0 ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
int i ;
const char * intf_std_name = " Unknown " ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] get current config core status code %d \n " , rv ) ;
2019-07-04 00:21:41 -04:00
if ( rv )
return ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Feature Header: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 8 ; i + + )
{
printf ( " %02X " , buf [ i ] ) ;
}
printf ( " \n " ) ;
if ( buf [ 6 ] = = 0 & & buf [ 7 ] = = 8 )
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Current Profile: CD-ROM \n " ) ;
2019-07-04 00:21:41 -04:00
else
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Current Profile: %02X%02X \n " , buf [ 6 ] , buf [ 7 ] ) ;
2019-07-04 00:21:41 -04:00
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Core Feature Descriptor: " ) ;
2019-07-04 00:21:41 -04:00
for ( i = 0 ; i < 12 ; i + + )
{
printf ( " %02X " , buf [ 8 + i ] ) ;
}
printf ( " \n " ) ;
intf_std = buf [ 8 + 4 ] < < 24 | buf [ 8 + 5 ] < < 16 | buf [ 8 + 6 ] < < 8 | buf [ 8 + 7 ] ;
switch ( intf_std )
{
case 0 :
intf_std_name = " Unspecified " ;
break ;
case 1 :
intf_std_name = " SCSI Family " ;
break ;
case 2 :
intf_std_name = " ATAPI " ;
break ;
case 7 :
intf_std_name = " Serial ATAPI " ;
break ;
case 8 :
intf_std_name = " USB " ;
break ;
default :
break ;
}
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Physical Interface Standard: %u (%s) \n " , intf_std , intf_std_name ) ;
2019-07-04 00:21:41 -04:00
}
2019-06-26 21:45:00 -04:00
int cdrom_read_subq ( libretro_vfs_implementation_file * stream , unsigned char * buf , size_t len )
2019-06-23 18:23:39 -04:00
{
/* MMC Command: READ TOC/PMA/ATIP */
unsigned char cdb [ ] = { 0x43 , 0x2 , 0x2 , 0 , 0 , 0 , 0x1 , 0x9 , 0x30 , 0 } ;
# ifdef CDROM_DEBUG
unsigned short data_len = 0 ;
unsigned char first_session = 0 ;
unsigned char last_session = 0 ;
int i ;
# endif
int rv ;
if ( ! buf )
return 1 ;
2019-06-26 21:45:00 -04:00
rv = cdrom_send_command ( stream , DIRECTION_IN , buf , len , cdb , sizeof ( cdb ) , 0 ) ;
2019-06-23 18:23:39 -04:00
if ( rv )
return 1 ;
# ifdef CDROM_DEBUG
data_len = buf [ 0 ] < < 8 | buf [ 1 ] ;
first_session = buf [ 2 ] ;
last_session = buf [ 3 ] ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Data Length: %d \n " , data_len ) ;
printf ( " [CDROM] First Session: %d \n " , first_session ) ;
printf ( " [CDROM] Last Session: %d \n " , last_session ) ;
2019-06-23 18:23:39 -04:00
for ( i = 0 ; i < ( data_len - 2 ) / 11 ; i + + )
{
unsigned char session_num = buf [ 4 + ( i * 11 ) + 0 ] ;
unsigned char adr = ( buf [ 4 + ( i * 11 ) + 1 ] > > 4 ) & 0xF ;
/*unsigned char control = buf[4 + (i * 11) + 1] & 0xF;*/
unsigned char tno = buf [ 4 + ( i * 11 ) + 2 ] ;
unsigned char point = buf [ 4 + ( i * 11 ) + 3 ] ;
unsigned char pmin = buf [ 4 + ( i * 11 ) + 8 ] ;
unsigned char psec = buf [ 4 + ( i * 11 ) + 9 ] ;
unsigned char pframe = buf [ 4 + ( i * 11 ) + 10 ] ;
/*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
/* why is control always 0? */
if ( /*(control == 4 || control == 6) && */ adr = = 1 & & tno = = 0 & & point > = 1 & & point < = 99 )
{
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] - Session#: %d TNO %d POINT %d " , session_num , tno , point ) ;
printf ( " [CDROM] Track start time: (MSF %02u:%02u:%02u) " , ( unsigned ) pmin , ( unsigned ) psec , ( unsigned ) pframe ) ;
2019-06-23 18:23:39 -04:00
}
else if ( /*(control == 4 || control == 6) && */ adr = = 1 & & tno = = 0 & & point = = 0xA0 )
{
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] - Session#: %d TNO %d POINT %d " , session_num , tno , point ) ;
printf ( " [CDROM] First Track Number: %d " , pmin ) ;
printf ( " [CDROM] Disc Type: %d " , psec ) ;
2019-06-23 18:23:39 -04:00
}
else if ( /*(control == 4 || control == 6) && */ adr = = 1 & & tno = = 0 & & point = = 0xA1 )
{
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] - Session#: %d TNO %d POINT %d " , session_num , tno , point ) ;
printf ( " [CDROM] Last Track Number: %d " , pmin ) ;
2019-06-23 18:23:39 -04:00
}
else if ( /*(control == 4 || control == 6) && */ adr = = 1 & & tno = = 0 & & point = = 0xA2 )
{
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] - Session#: %d TNO %d POINT %d " , session_num , tno , point ) ;
printf ( " [CDROM] Lead-out runtime: (MSF %02u:%02u:%02u) " , ( unsigned ) pmin , ( unsigned ) psec , ( unsigned ) pframe ) ;
2019-06-23 18:23:39 -04:00
}
printf ( " \n " ) ;
}
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-23 18:23:39 -04:00
# endif
return 0 ;
}
2019-06-26 21:45:00 -04:00
static int cdrom_read_track_info ( libretro_vfs_implementation_file * stream , unsigned char track , cdrom_toc_t * toc )
2019-06-23 18:23:39 -04:00
{
/* MMC Command: READ TRACK INFORMATION */
2019-07-09 16:46:53 -04:00
unsigned char cdb [ ] = { 0x52 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0x80 , 0 } ;
2019-06-23 18:23:39 -04:00
unsigned char buf [ 384 ] = { 0 } ;
unsigned lba = 0 ;
unsigned track_size = 0 ;
2019-07-09 16:46:53 -04:00
int rv ;
2019-07-08 15:32:12 -04:00
ssize_t pregap_lba_len ;
2019-06-23 18:23:39 -04:00
2019-07-09 16:46:53 -04:00
cdb [ 5 ] = track ;
rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
2019-06-23 18:23:39 -04:00
if ( rv )
return 1 ;
memcpy ( & lba , buf + 8 , 4 ) ;
memcpy ( & track_size , buf + 24 , 4 ) ;
lba = swap_if_little32 ( lba ) ;
track_size = swap_if_little32 ( track_size ) ;
2019-06-25 02:51:51 -04:00
/* lba_start may be earlier than the MSF start times seen in read_subq */
2019-06-23 18:23:39 -04:00
toc - > track [ track - 1 ] . lba_start = lba ;
toc - > track [ track - 1 ] . track_size = track_size ;
2019-07-08 15:32:12 -04:00
pregap_lba_len = ( toc - > track [ track - 1 ] . audio ? 0 : ( toc - > track [ track - 1 ] . lba - toc - > track [ track - 1 ] . lba_start ) ) ;
toc - > track [ track - 1 ] . track_bytes = ( track_size - pregap_lba_len ) * 2352 ;
2019-07-06 20:16:47 -04:00
toc - > track [ track - 1 ] . mode = buf [ 6 ] & 0xF ;
2019-06-23 18:23:39 -04:00
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Track %d Info: " , track ) ;
printf ( " [CDROM] Copy: %d " , ( buf [ 5 ] & 0x10 ) > 0 ) ;
2019-07-15 17:16:19 -04:00
printf ( " [CDROM] Data Mode: %d " , toc - > track [ track - 1 ] . mode ) ;
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] LBA Start: %d (%d) " , lba , toc - > track [ track - 1 ] . lba ) ;
printf ( " [CDROM] Track Size: %d \n " , track_size ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-23 18:23:39 -04:00
# endif
return 0 ;
}
2019-06-29 20:03:59 -04:00
int cdrom_set_read_speed ( libretro_vfs_implementation_file * stream , unsigned speed )
{
/* MMC Command: SET CD SPEED */
2019-07-09 16:46:53 -04:00
unsigned char cmd [ ] = { 0xBB , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
cmd [ 2 ] = ( speed > > 24 ) & 0xFF ;
cmd [ 3 ] = ( speed > > 16 ) & 0xFF ;
cmd [ 4 ] = ( speed > > 8 ) & 0xFF ;
cmd [ 5 ] = speed & 0xFF ;
2019-06-29 20:03:59 -04:00
return cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cmd , sizeof ( cmd ) , 0 ) ;
}
2019-06-26 21:45:00 -04:00
int cdrom_write_cue ( libretro_vfs_implementation_file * stream , char * * out_buf , size_t * out_len , char cdrom_drive , unsigned char * num_tracks , cdrom_toc_t * toc )
2019-06-23 18:23:39 -04:00
{
unsigned char buf [ 2352 ] = { 0 } ;
unsigned short data_len = 0 ;
size_t len = 0 ;
size_t pos = 0 ;
int rv = 0 ;
int i ;
if ( ! out_buf | | ! out_len | | ! num_tracks | | ! toc )
{
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Invalid buffer/length pointer for CDROM cue sheet \n " ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-23 18:23:39 -04:00
# endif
return 1 ;
}
2019-06-29 20:03:59 -04:00
cdrom_set_read_speed ( stream , 0xFFFFFFFF ) ;
2019-06-26 21:45:00 -04:00
rv = cdrom_read_subq ( stream , buf , sizeof ( buf ) ) ;
2019-06-23 18:23:39 -04:00
if ( rv )
return rv ;
data_len = buf [ 0 ] < < 8 | buf [ 1 ] ;
for ( i = 0 ; i < ( data_len - 2 ) / 11 ; i + + )
{
unsigned char adr = ( buf [ 4 + ( i * 11 ) + 1 ] > > 4 ) & 0xF ;
unsigned char tno = buf [ 4 + ( i * 11 ) + 2 ] ;
unsigned char point = buf [ 4 + ( i * 11 ) + 3 ] ;
unsigned char pmin = buf [ 4 + ( i * 11 ) + 8 ] ;
if ( /*(control == 4 || control == 6) && */ adr = = 1 & & tno = = 0 & & point = = 0xA1 )
{
* num_tracks = pmin ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Number of CDROM tracks: %d \n " , * num_tracks ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-23 18:23:39 -04:00
# endif
break ;
}
}
if ( ! * num_tracks | | * num_tracks > 99 )
{
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Invalid number of CDROM tracks: %d \n " , * num_tracks ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-23 18:23:39 -04:00
# endif
return 1 ;
}
len = CDROM_CUE_TRACK_BYTES * ( * num_tracks ) ;
toc - > num_tracks = * num_tracks ;
* out_buf = ( char * ) calloc ( 1 , len ) ;
* out_len = len ;
for ( i = 0 ; i < ( data_len - 2 ) / 11 ; i + + )
{
/*unsigned char session_num = buf[4 + (i * 11) + 0];*/
unsigned char adr = ( buf [ 4 + ( i * 11 ) + 1 ] > > 4 ) & 0xF ;
2019-06-25 19:34:29 -04:00
unsigned char control = buf [ 4 + ( i * 11 ) + 1 ] & 0xF ;
2019-06-23 18:23:39 -04:00
unsigned char tno = buf [ 4 + ( i * 11 ) + 2 ] ;
unsigned char point = buf [ 4 + ( i * 11 ) + 3 ] ;
2019-07-07 02:40:38 -04:00
/*unsigned char amin = buf[4 + (i * 11) + 4];
unsigned char asec = buf [ 4 + ( i * 11 ) + 5 ] ;
unsigned char aframe = buf [ 4 + ( i * 11 ) + 6 ] ; */
2019-06-23 18:23:39 -04:00
unsigned char pmin = buf [ 4 + ( i * 11 ) + 8 ] ;
unsigned char psec = buf [ 4 + ( i * 11 ) + 9 ] ;
unsigned char pframe = buf [ 4 + ( i * 11 ) + 10 ] ;
2019-07-04 23:05:28 -04:00
unsigned lba = cdrom_msf_to_lba ( pmin , psec , pframe ) ;
2019-06-23 18:23:39 -04:00
2019-07-07 02:40:38 -04:00
/*printf("i %d control %d adr %d tno %d point %d: amin %d asec %d aframe %d pmin %d psec %d pframe %d\n", i, control, adr, tno, point, amin, asec, aframe, pmin, psec, pframe);*/
2019-06-23 18:23:39 -04:00
/* why is control always 0? */
if ( /*(control == 4 || control == 6) && */ adr = = 1 & & tno = = 0 & & point > = 1 & & point < = 99 )
{
bool audio = false ;
const char * track_type = " MODE1/2352 " ;
2019-06-25 19:34:29 -04:00
audio = ( ! ( control & 0x4 ) & & ! ( control & 0x5 ) ) ;
2019-06-23 18:23:39 -04:00
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Track %02d CONTROL %01X ADR %01X AUDIO? %d \n " , point , control , adr , audio ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-23 18:23:39 -04:00
# endif
toc - > track [ point - 1 ] . track_num = point ;
toc - > track [ point - 1 ] . min = pmin ;
toc - > track [ point - 1 ] . sec = psec ;
toc - > track [ point - 1 ] . frame = pframe ;
2019-06-30 01:47:29 -04:00
toc - > track [ point - 1 ] . lba = lba ;
2019-06-23 18:23:39 -04:00
toc - > track [ point - 1 ] . audio = audio ;
2019-07-06 20:16:47 -04:00
cdrom_read_track_info ( stream , point , toc ) ;
2019-06-23 18:23:39 -04:00
if ( audio )
track_type = " AUDIO " ;
2019-07-06 20:16:47 -04:00
else if ( toc - > track [ point - 1 ] . mode = = 1 )
2019-06-23 18:23:39 -04:00
track_type = " MODE1/2352 " ;
2019-07-06 20:16:47 -04:00
else if ( toc - > track [ point - 1 ] . mode = = 2 )
2019-06-23 18:23:39 -04:00
track_type = " MODE2/2352 " ;
2019-07-03 14:19:16 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-07-06 17:23:10 -04:00
pos + = snprintf ( * out_buf + pos , len - pos , " FILE \" cdrom://%c:/drive-track%02d.bin \" BINARY \n " , cdrom_drive , point ) ;
2019-06-29 13:28:24 -04:00
# else
2019-06-25 02:51:51 -04:00
pos + = snprintf ( * out_buf + pos , len - pos , " FILE \" cdrom://drive%c-track%02d.bin \" BINARY \n " , cdrom_drive , point ) ;
2019-06-29 13:28:24 -04:00
# endif
2019-06-23 18:23:39 -04:00
pos + = snprintf ( * out_buf + pos , len - pos , " TRACK %02d %s \n " , point , track_type ) ;
2019-07-02 00:12:00 -04:00
{
unsigned pregap_lba_len = toc - > track [ point - 1 ] . lba - toc - > track [ point - 1 ] . lba_start ;
if ( toc - > track [ point - 1 ] . audio & & pregap_lba_len > 0 )
{
unsigned char min = 0 ;
unsigned char sec = 0 ;
unsigned char frame = 0 ;
2019-07-04 23:05:28 -04:00
cdrom_lba_to_msf ( pregap_lba_len , & min , & sec , & frame ) ;
2019-07-02 00:12:00 -04:00
pos + = snprintf ( * out_buf + pos , len - pos , " INDEX 00 00:00:00 \n " ) ;
pos + = snprintf ( * out_buf + pos , len - pos , " INDEX 01 %02u:%02u:%02u \n " , ( unsigned ) min , ( unsigned ) sec , ( unsigned ) frame ) ;
}
else
pos + = snprintf ( * out_buf + pos , len - pos , " INDEX 01 00:00:00 \n " ) ;
}
2019-06-23 18:23:39 -04:00
}
}
return 0 ;
}
/* needs 32 bytes for full vendor, product and version */
2019-07-21 12:06:01 -04:00
int cdrom_get_inquiry ( libretro_vfs_implementation_file * stream , char * model , int len , bool * is_cdrom )
2019-06-23 18:23:39 -04:00
{
/* MMC Command: INQUIRY */
unsigned char cdb [ ] = { 0x12 , 0 , 0 , 0 , 0xff , 0 } ;
unsigned char buf [ 256 ] = { 0 } ;
2019-06-26 21:45:00 -04:00
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
2019-07-04 00:21:41 -04:00
bool cdrom = false ;
2019-06-23 18:23:39 -04:00
if ( rv )
return 1 ;
if ( model & & len > = 32 )
{
memset ( model , 0 , len ) ;
/* vendor */
memcpy ( model , buf + 8 , 8 ) ;
model [ 8 ] = ' ' ;
/* product */
memcpy ( model + 9 , buf + 16 , 16 ) ;
model [ 25 ] = ' ' ;
/* version */
memcpy ( model + 26 , buf + 32 , 4 ) ;
}
2019-07-04 00:21:41 -04:00
cdrom = ( buf [ 0 ] = = 5 ) ;
if ( is_cdrom & & cdrom )
2019-07-03 14:19:16 -04:00
* is_cdrom = true ;
2019-07-04 00:21:41 -04:00
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] Device Model: %s (is CD-ROM? %s) \n " , model , ( cdrom ? " yes " : " no " ) ) ;
2019-07-04 00:21:41 -04:00
# endif
2019-06-23 18:23:39 -04:00
return 0 ;
}
2019-07-06 20:16:47 -04:00
int cdrom_read ( libretro_vfs_implementation_file * stream , cdrom_group_timeouts_t * timeouts , unsigned char min , unsigned char sec , unsigned char frame , void * s , size_t len , size_t skip )
2019-06-23 18:23:39 -04:00
{
/* MMC Command: READ CD MSF */
2019-07-09 16:46:53 -04:00
unsigned char cdb [ ] = { 0xB9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xF8 , 0 , 0 } ;
2019-06-23 18:23:39 -04:00
int rv ;
2019-07-21 12:06:01 -04:00
double frames = ceil ( ( len + skip ) / 2352.0 ) ;
unsigned frame_end = cdrom_msf_to_lba ( min , sec , frame ) + frames ;
2019-06-23 18:23:39 -04:00
2019-07-09 16:46:53 -04:00
cdb [ 3 ] = min ;
cdb [ 4 ] = sec ;
cdb [ 5 ] = frame ;
2019-07-21 12:06:01 -04:00
if ( frames < = 1 )
2019-06-23 18:23:39 -04:00
{
2019-07-21 12:06:01 -04:00
cdrom_lba_to_msf ( frame_end , & cdb [ 6 ] , & cdb [ 7 ] , & cdb [ 8 ] ) ;
2019-06-25 02:51:51 -04:00
# ifdef CDROM_DEBUG
2019-07-21 12:06:01 -04:00
printf ( " [CDROM] single-frame read: %d %d %d skip % " PRId64 " \n " , cdb [ 3 ] , cdb [ 4 ] , cdb [ 5 ] , skip ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-06-23 18:23:39 -04:00
}
else
{
2019-07-06 21:54:10 -04:00
cdrom_lba_to_msf ( frame_end , & cdb [ 6 ] , & cdb [ 7 ] , & cdb [ 8 ] ) ;
2019-06-23 18:23:39 -04:00
2019-06-25 02:51:51 -04:00
# ifdef CDROM_DEBUG
2019-07-21 12:06:01 -04:00
printf ( " [CDROM] multi-frame read: %d sectors starting from %02d:%02d:%02d skip % " PRId64 " \n " , ( int ) frames , cdb [ 3 ] , cdb [ 4 ] , cdb [ 5 ] , skip ) ;
2019-06-28 18:14:04 -04:00
fflush ( stdout ) ;
2019-06-25 02:51:51 -04:00
# endif
2019-06-23 18:23:39 -04:00
}
2019-07-21 12:06:01 -04:00
/* regardless of the length specified here, a new buffer will be allocated and padded to a sector multiple inside cdrom_send_command */
2019-06-26 21:45:00 -04:00
rv = cdrom_send_command ( stream , DIRECTION_IN , s , len , cdb , sizeof ( cdb ) , skip ) ;
2019-06-23 18:23:39 -04:00
2019-07-04 18:20:05 -04:00
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] read msf status code %d \n " , rv ) ;
2019-07-04 18:20:05 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
{
2019-07-21 12:06:01 -04:00
stream - > cdrom . last_frame_valid = false ;
2019-06-23 18:23:39 -04:00
return 1 ;
2019-07-21 12:06:01 -04:00
}
2019-06-23 18:23:39 -04:00
return 0 ;
}
2019-07-21 12:06:01 -04:00
int cdrom_stop ( libretro_vfs_implementation_file * stream )
2019-07-02 21:35:20 -04:00
{
/* MMC Command: START STOP UNIT */
unsigned char cdb [ ] = { 0x1B , 0 , 0 , 0 , 0x0 , 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] stop status code %d \n " , rv ) ;
2019-07-02 21:35:20 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return 1 ;
return 0 ;
}
2019-07-21 12:06:01 -04:00
int cdrom_unlock ( libretro_vfs_implementation_file * stream )
2019-07-02 21:35:20 -04:00
{
/* MMC Command: PREVENT ALLOW MEDIUM REMOVAL */
unsigned char cdb [ ] = { 0x1E , 0 , 0 , 0 , 0x2 , 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] persistent prevent clear status code %d \n " , rv ) ;
2019-07-02 21:35:20 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return 1 ;
cdb [ 4 ] = 0x0 ;
rv = cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] prevent clear status code %d \n " , rv ) ;
2019-07-02 21:35:20 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return 1 ;
return 0 ;
}
2019-07-21 12:06:01 -04:00
int cdrom_open_tray ( libretro_vfs_implementation_file * stream )
2019-07-02 21:35:20 -04:00
{
/* MMC Command: START STOP UNIT */
unsigned char cdb [ ] = { 0x1B , 0 , 0 , 0 , 0x2 , 0 } ;
int rv ;
cdrom_unlock ( stream ) ;
cdrom_stop ( stream ) ;
rv = cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] open tray status code %d \n " , rv ) ;
2019-07-02 21:35:20 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return 1 ;
return 0 ;
}
2019-07-21 12:06:01 -04:00
int cdrom_close_tray ( libretro_vfs_implementation_file * stream )
2019-07-02 21:35:20 -04:00
{
/* MMC Command: START STOP UNIT */
unsigned char cdb [ ] = { 0x1B , 0 , 0 , 0 , 0x3 , 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] close tray status code %d \n " , rv ) ;
2019-07-02 21:35:20 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return 1 ;
return 0 ;
}
2019-07-03 14:19:16 -04:00
struct string_list * cdrom_get_available_drives ( void )
{
struct string_list * list = string_list_new ( ) ;
# if defined(__linux__) && !defined(ANDROID)
struct string_list * dir_list = dir_list_new ( " /dev " , NULL , false , false , false , false ) ;
int i ;
if ( ! dir_list )
return list ;
2019-07-09 22:32:11 -04:00
for ( i = 0 ; i < ( int ) dir_list - > size ; i + + )
2019-07-03 14:19:16 -04:00
{
if ( strstr ( dir_list - > elems [ i ] . data , " /dev/sg " ) )
{
char drive_model [ 32 ] = { 0 } ;
2019-07-08 15:52:57 -04:00
char drive_string [ 33 ] = { 0 } ;
2019-07-03 14:19:16 -04:00
union string_list_elem_attr attr = { 0 } ;
int dev_index = 0 ;
RFILE * file = filestream_open ( dir_list - > elems [ i ] . data , RETRO_VFS_FILE_ACCESS_READ , 0 ) ;
2019-07-21 12:06:01 -04:00
libretro_vfs_implementation_file * stream ;
2019-07-03 14:19:16 -04:00
bool is_cdrom = false ;
if ( ! file )
continue ;
stream = filestream_get_vfs_handle ( file ) ;
cdrom_get_inquiry ( stream , drive_model , sizeof ( drive_model ) , & is_cdrom ) ;
filestream_close ( file ) ;
if ( ! is_cdrom )
continue ;
sscanf ( dir_list - > elems [ i ] . data + strlen ( " /dev/sg " ) , " %d " , & dev_index ) ;
2019-07-07 02:40:38 -04:00
dev_index = ' 0 ' + dev_index ;
2019-07-03 14:19:16 -04:00
attr . i = dev_index ;
if ( ! string_is_empty ( drive_model ) )
strlcat ( drive_string , drive_model , sizeof ( drive_string ) ) ;
else
strlcat ( drive_string , " Unknown Drive " , sizeof ( drive_string ) ) ;
string_list_append ( list , drive_string , attr ) ;
}
}
string_list_free ( dir_list ) ;
# endif
2019-07-03 16:05:15 -04:00
# if defined(_WIN32) && !defined(_XBOX)
2019-07-03 17:18:28 -04:00
DWORD drive_mask = GetLogicalDrives ( ) ;
int i ;
for ( i = 0 ; i < sizeof ( DWORD ) * 8 ; i + + )
{
char path [ ] = { " a: \\ " } ;
char cdrom_path [ ] = { " cdrom://a:/drive-track01.bin " } ;
path [ 0 ] + = i ;
cdrom_path [ 8 ] + = i ;
/* this drive letter doesn't exist */
if ( ! ( drive_mask & ( 1 < < i ) ) )
continue ;
if ( GetDriveType ( path ) ! = DRIVE_CDROM )
continue ;
else
{
char drive_model [ 32 ] = { 0 } ;
2019-07-08 15:52:57 -04:00
char drive_string [ 33 ] = { 0 } ;
2019-07-03 17:18:28 -04:00
union string_list_elem_attr attr = { 0 } ;
2019-07-04 14:04:25 -04:00
RFILE * file = filestream_open ( cdrom_path , RETRO_VFS_FILE_ACCESS_READ , 0 ) ;
2019-07-21 12:06:01 -04:00
libretro_vfs_implementation_file * stream ;
2019-07-03 17:18:28 -04:00
bool is_cdrom = false ;
if ( ! file )
continue ;
stream = filestream_get_vfs_handle ( file ) ;
cdrom_get_inquiry ( stream , drive_model , sizeof ( drive_model ) , & is_cdrom ) ;
filestream_close ( file ) ;
if ( ! is_cdrom )
continue ;
attr . i = path [ 0 ] ;
if ( ! string_is_empty ( drive_model ) )
strlcat ( drive_string , drive_model , sizeof ( drive_string ) ) ;
else
strlcat ( drive_string , " Unknown Drive " , sizeof ( drive_string ) ) ;
string_list_append ( list , drive_string , attr ) ;
}
}
2019-07-03 16:05:15 -04:00
# endif
2019-07-03 14:19:16 -04:00
return list ;
}
2019-07-21 12:06:01 -04:00
bool cdrom_is_media_inserted ( libretro_vfs_implementation_file * stream )
2019-07-04 00:21:41 -04:00
{
/* MMC Command: TEST UNIT READY */
unsigned char cdb [ ] = { 0x00 , 0 , 0 , 0 , 0 , 0 } ;
int rv = cdrom_send_command ( stream , DIRECTION_NONE , NULL , 0 , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] media inserted status code %d \n " , rv ) ;
2019-07-04 00:21:41 -04:00
fflush ( stdout ) ;
# endif
/* Will also return false if the drive is simply not ready yet (tray open, disc spinning back up after tray closed etc).
* Command will not block or wait for media to become ready . */
if ( rv )
return false ;
return true ;
}
2019-07-10 11:17:28 -04:00
bool cdrom_drive_has_media ( const char drive )
{
RFILE * file ;
char cdrom_path_bin [ 256 ] ;
cdrom_path_bin [ 0 ] = ' \0 ' ;
cdrom_device_fillpath ( cdrom_path_bin , sizeof ( cdrom_path_bin ) , drive , 1 , false ) ;
file = filestream_open ( cdrom_path_bin , RETRO_VFS_FILE_ACCESS_READ , 0 ) ;
if ( file )
{
2019-07-21 12:06:01 -04:00
libretro_vfs_implementation_file * stream = filestream_get_vfs_handle ( file ) ;
2019-07-10 11:17:28 -04:00
bool has_media = false ;
has_media = cdrom_is_media_inserted ( stream ) ;
filestream_close ( file ) ;
return has_media ;
}
return false ;
}
2019-07-21 12:06:01 -04:00
bool cdrom_set_read_cache ( libretro_vfs_implementation_file * stream , bool enabled )
2019-07-05 23:45:48 -04:00
{
/* MMC Command: MODE SENSE (10) and MODE SELECT (10) */
unsigned char cdb_sense_changeable [ ] = { 0x5A , 0 , 0x48 , 0 , 0 , 0 , 0 , 0 , 0x14 , 0 } ;
unsigned char cdb_sense [ ] = { 0x5A , 0 , 0x8 , 0 , 0 , 0 , 0 , 0 , 0x14 , 0 } ;
unsigned char cdb_select [ ] = { 0x55 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0x14 , 0 } ;
unsigned char buf [ 20 ] = { 0 } ;
int rv , i ;
rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb_sense_changeable , sizeof ( cdb_sense_changeable ) , 0 ) ;
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] mode sense changeable status code %d \n " , rv ) ;
2019-07-05 23:45:48 -04:00
fflush ( stdout ) ;
# endif
if ( rv )
return false ;
if ( ! ( buf [ 10 ] & 0x1 ) )
{
/* RCD (read cache disable) bit is not changeable */
# ifdef CDROM_DEBUG
2019-07-10 20:56:23 -04:00
printf ( " [CDROM] RCD (read cache disable) bit is not changeable. \n " ) ;
2019-07-05 23:45:48 -04:00
fflush ( stdout ) ;
# endif
return false ;
}
memset ( buf , 0 , sizeof ( buf ) ) ;
rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb_sense , sizeof ( cdb_sense ) , 0 ) ;
# ifdef CDROM_DEBUG
printf ( " mode sense status code %d \n " , rv ) ;
fflush ( stdout ) ;
# endif
if ( rv )
return false ;
# ifdef CDROM_DEBUG
printf ( " Mode sense data for caching mode page: " ) ;
2019-07-09 22:34:28 -04:00
for ( i = 0 ; i < ( int ) sizeof ( buf ) ; i + + )
2019-07-05 23:45:48 -04:00
{
printf ( " %02X " , buf [ i ] ) ;
}
printf ( " \n " ) ;
fflush ( stdout ) ;
# endif
/* "When transferred during execution of the MODE SELECT (10) command, Mode Data Length is reserved." */
for ( i = 0 ; i < 8 ; i + + )
buf [ i ] = 0 ;
if ( enabled )
buf [ 10 ] & = ~ 1 ;
else
buf [ 10 ] | = 1 ;
rv = cdrom_send_command ( stream , DIRECTION_OUT , buf , sizeof ( buf ) , cdb_select , sizeof ( cdb_select ) , 0 ) ;
# ifdef CDROM_DEBUG
printf ( " mode select status code %d \n " , rv ) ;
fflush ( stdout ) ;
# endif
if ( rv )
return false ;
return true ;
}
2019-07-06 20:16:47 -04:00
bool cdrom_get_timeouts ( libretro_vfs_implementation_file * stream , cdrom_group_timeouts_t * timeouts )
{
/* MMC Command: MODE SENSE (10) */
2019-07-15 17:16:19 -04:00
int rv ;
2019-07-09 09:23:47 +02:00
unsigned char cdb [ ] = { 0x5A , 0 , 0x1D , 0 , 0 , 0 , 0 , 0 , 0x14 , 0 } ;
2019-07-06 20:16:47 -04:00
unsigned char buf [ 20 ] = { 0 } ;
2019-07-09 09:23:47 +02:00
unsigned short g1 = 0 ;
unsigned short g2 = 0 ;
unsigned short g3 = 0 ;
2019-07-06 20:16:47 -04:00
if ( ! timeouts )
return false ;
rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
# ifdef CDROM_DEBUG
printf ( " get timeouts status code %d \n " , rv ) ;
fflush ( stdout ) ;
# endif
if ( rv )
return false ;
g1 = buf [ 14 ] < < 8 | buf [ 15 ] ;
g2 = buf [ 16 ] < < 8 | buf [ 17 ] ;
g3 = buf [ 18 ] < < 8 | buf [ 19 ] ;
# ifdef CDROM_DEBUG
{
2019-07-15 17:16:19 -04:00
int i ;
2019-07-06 20:16:47 -04:00
2019-07-15 17:16:19 -04:00
printf ( " Mode sense data for timeout groups: " ) ;
2019-07-06 20:16:47 -04:00
2019-07-15 17:16:19 -04:00
for ( i = 0 ; i < ( int ) sizeof ( buf ) ; i + + )
{
printf ( " %02X " , buf [ i ] ) ;
}
2019-07-06 20:16:47 -04:00
2019-07-15 17:16:19 -04:00
printf ( " \n " ) ;
printf ( " Group 1 Timeout: %d \n " , g1 ) ;
printf ( " Group 2 Timeout: %d \n " , g2 ) ;
printf ( " Group 3 Timeout: %d \n " , g3 ) ;
fflush ( stdout ) ;
}
2019-07-06 20:16:47 -04:00
# endif
timeouts - > g1_timeout = g1 ;
timeouts - > g2_timeout = g2 ;
timeouts - > g3_timeout = g3 ;
return true ;
}
2019-07-07 02:40:38 -04:00
2019-07-21 12:06:01 -04:00
bool cdrom_has_atip ( libretro_vfs_implementation_file * stream )
2019-07-07 02:40:38 -04:00
{
/* MMC Command: READ TOC/PMA/ATIP */
unsigned char cdb [ ] = { 0x43 , 0x2 , 0x4 , 0 , 0 , 0 , 0 , 0x9 , 0x30 , 0 } ;
unsigned char buf [ 32 ] = { 0 } ;
unsigned short atip_len = 0 ;
int rv = cdrom_send_command ( stream , DIRECTION_IN , buf , sizeof ( buf ) , cdb , sizeof ( cdb ) , 0 ) ;
if ( rv )
return false ;
atip_len = buf [ 0 ] < < 8 | buf [ 1 ] ;
# ifdef CDROM_DEBUG
printf ( " ATIP Length %d, Disc Type %d, Disc Sub-Type %d \n " , atip_len , ( buf [ 6 ] > > 6 ) & 0x1 , ( ( buf [ 6 ] > > 5 ) & 0x1 ) < < 2 | ( ( buf [ 6 ] > > 4 ) & 0x1 ) < < 1 | ( ( buf [ 6 ] > > 3 ) & 0x1 ) < < 0 ) ;
# endif
if ( atip_len < 5 )
return false ;
return true ;
}
2019-07-08 15:32:12 -04:00
void cdrom_device_fillpath ( char * path , size_t len , char drive , unsigned char track , bool is_cue )
{
size_t pos = 0 ;
if ( ! path | | len = = 0 )
return ;
if ( is_cue )
{
# ifdef _WIN32
pos = strlcpy ( path , " cdrom:// " , len ) ;
if ( len > pos )
path [ pos + + ] = drive ;
pos = strlcat ( path , " :/drive.cue " , len ) ;
# else
# ifdef __linux__
pos = strlcpy ( path , " cdrom://drive " , len ) ;
if ( len > pos )
path [ pos + + ] = drive ;
pos = strlcat ( path , " .cue " , len ) ;
# endif
# endif
}
else
{
# ifdef _WIN32
pos = strlcpy ( path , " cdrom:// " , len ) ;
if ( len > pos )
path [ pos + + ] = drive ;
pos + = snprintf ( path + pos , len - pos , " :/drive-track%02d.bin " , track ) ;
# else
# ifdef __linux__
pos = strlcpy ( path , " cdrom://drive " , len ) ;
if ( len > pos )
path [ pos + + ] = drive ;
pos + = snprintf ( path + pos , len - pos , " -track%02d.bin " , track ) ;
# endif
# endif
}
}