1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-05 09:48:42 +00:00

track1 playback is working, redbook might have issues currently

This commit is contained in:
Brad Parker 2019-06-25 02:51:51 -04:00
parent 0ad77800d9
commit 8af3078966
7 changed files with 514 additions and 300 deletions

View File

@ -1623,7 +1623,8 @@ ifeq ($(HAVE_CDROM), 1)
endif
DEFINES += -DHAVE_CDROM
OBJ += $(LIBRETRO_COMM_DIR)/cdrom/cdrom.o
OBJ += $(LIBRETRO_COMM_DIR)/cdrom/cdrom.o \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_cdrom.o
endif
ifeq ($(HAVE_RTGA), 1)

View File

@ -40,7 +40,7 @@
#include <scsi/sg.h>
#endif
#define CDROM_CUE_TRACK_BYTES 78
#define CDROM_CUE_TRACK_BYTES 86
typedef enum
{
@ -76,16 +76,23 @@ void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
*frame = (*frame < 74) ? (*frame + 1) : 0;
}
static int cdrom_send_command(int fd, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len)
static int cdrom_send_command(int fd, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, size_t skip)
{
#ifdef __linux__
sg_io_hdr_t sgio = {0};
unsigned char sense[SG_MAX_SENSE] = {0};
unsigned char *xfer_buf;
int rv;
unsigned char retries_left = 5;
if (!cmd || cmd_len == 0)
return 1;
xfer_buf = (unsigned char*)calloc(1, len + skip);
if (!xfer_buf)
return 1;
sgio.interface_id = 'S';
switch (dir)
@ -105,23 +112,42 @@ static int cdrom_send_command(int fd, CDROM_CMD_Direction dir, void *buf, size_t
sgio.cmd_len = cmd_len;
sgio.cmdp = cmd;
if (buf)
sgio.dxferp = buf;
if (xfer_buf)
sgio.dxferp = xfer_buf;
if (len)
sgio.dxfer_len = len;
sgio.dxfer_len = len + skip;
sgio.sbp = sense;
sgio.mx_sb_len = sizeof(sense);
sgio.timeout = 30000;
retry:
rv = ioctl(fd, SG_IO, &sgio);
#ifdef CDROM_DEBUG
if (sgio.info & SG_INFO_CHECK)
{
unsigned i;
const char *sense_key_text = NULL;
if ((sense[2] & 0xF) == 3)
{
if (retries_left)
{
#ifdef CDROM_DEBUG
printf("CDROM Read Retry...\n");
#endif
retries_left--;
goto retry;
}
else
{
#ifdef CDROM_DEBUG
printf("CDROM Read Retries failed, giving up.\n");
#endif
}
}
#ifdef CDROM_DEBUG
printf("CHECK CONDITION\n");
for (i = 0; i < SG_MAX_SENSE; i++)
@ -136,11 +162,65 @@ static int cdrom_send_command(int fd, CDROM_CMD_Direction dir, void *buf, size_t
if (sense[0] == 0x71)
printf("DEFERRED ERROR:\n");
printf("Sense Key: %02X\n", sense[2] & 0xF);
switch (sense[2] & 0xF)
{
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;
}
printf("Sense Key: %02X (%s)\n", sense[2] & 0xF, sense_key_text);
printf("ASC: %02X\n", sense[12]);
printf("ASCQ: %02X\n", sense[13]);
}
#endif
}
if (rv == 0 && buf)
{
memcpy(buf, xfer_buf + skip, len);
}
if (xfer_buf)
free(xfer_buf);
if (rv == -1)
return 1;
@ -173,7 +253,7 @@ int cdrom_read_subq(int fd, unsigned char *buf, size_t len)
if (!buf)
return 1;
rv = cdrom_send_command(fd, DIRECTION_IN, buf, len, cdb, sizeof(cdb));
rv = cdrom_send_command(fd, DIRECTION_IN, buf, len, cdb, sizeof(cdb), 0);
if (rv)
return 1;
@ -236,7 +316,7 @@ static int cdrom_read_track_info(int fd, unsigned char track, cdrom_toc_t *toc)
unsigned char buf[384] = {0};
unsigned lba = 0;
unsigned track_size = 0;
int rv = cdrom_send_command(fd, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb));
int rv = cdrom_send_command(fd, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
if (rv)
return 1;
@ -247,6 +327,7 @@ static int cdrom_read_track_info(int fd, unsigned char track, cdrom_toc_t *toc)
lba = swap_if_little32(lba);
track_size = swap_if_little32(track_size);
/* lba_start may be earlier than the MSF start times seen in read_subq */
toc->track[track - 1].lba_start = lba;
toc->track[track - 1].track_size = track_size;
@ -341,7 +422,7 @@ int cdrom_write_cue(int fd, char **out_buf, size_t *out_len, char cdrom_drive, u
bool audio = false;
const char *track_type = "MODE1/2352";
rv = cdrom_send_command(fd, DIRECTION_IN, q_buf, sizeof(q_buf), q_cdb, sizeof(q_cdb));
rv = cdrom_send_command(fd, DIRECTION_IN, q_buf, sizeof(q_buf), q_cdb, sizeof(q_cdb), 0);
if (rv)
continue;
@ -367,11 +448,11 @@ int cdrom_write_cue(int fd, char **out_buf, size_t *out_len, char cdrom_drive, u
else if (mode == 2)
track_type = "MODE2/2352";
pos += snprintf(*out_buf + pos, len - pos, "FILE \"cdrom://drive%c.bin\" BINARY\n", cdrom_drive);
cdrom_read_track_info(fd, point, toc);
pos += snprintf(*out_buf + pos, len - pos, "FILE \"cdrom://drive%c-track%02d.bin\" BINARY\n", cdrom_drive, point);
pos += snprintf(*out_buf + pos, len - pos, " TRACK %02d %s\n", point, track_type);
pos += snprintf(*out_buf + pos, len - pos, " INDEX 01 %02d:%02d:%02d\n", pmin, psec, pframe);
cdrom_read_track_info(fd, point, toc);
}
}
@ -384,7 +465,7 @@ int cdrom_get_inquiry(int fd, char *model, int len)
/* MMC Command: INQUIRY */
unsigned char cdb[] = {0x12, 0, 0, 0, 0xff, 0};
unsigned char buf[256] = {0};
int rv = cdrom_send_command(fd, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb));
int rv = cdrom_send_command(fd, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
if (rv)
return 1;
@ -410,13 +491,13 @@ int cdrom_get_inquiry(int fd, char *model, int len)
return 0;
}
int cdrom_read(int fd, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len)
int cdrom_read(int fd, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip)
{
/* MMC Command: READ CD MSF */
unsigned char cdb[] = {0xB9, 0, 0, min, sec, frame, 0, 0, 0, 0xF8, 0, 0};
int rv;
if (len <= 2352)
if (len + skip <= 2352)
{
unsigned char next_min = (frame == 74) ? (sec < 59 ? min : min + 1) : min;
unsigned char next_sec = (frame == 74) ? (sec < 59 ? (sec + 1) : 0) : sec;
@ -425,29 +506,23 @@ int cdrom_read(int fd, unsigned char min, unsigned char sec, unsigned char frame
cdb[6] = next_min;
cdb[7] = next_sec;
cdb[8] = next_frame;
#ifdef CDROM_DEBUG
printf("single-frame read: from %d %d %d to %d %d %d skip %ld\n", cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], skip);
#endif
}
else
{
unsigned frames = round(len / 2352.0);
unsigned frames = msf_to_lba(min, sec, frame) + round((len + skip) / 2352.0);
cdb[6] = frames / 75 / 60;
cdb[7] = frames / 75;
cdb[8] = frames - ((cdb[6] * 75 * 60) + (cdb[7] * 75));
lba_to_msf(frames, &cdb[6], &cdb[7], &cdb[8]);
if (cdb[8] > 74)
{
cdb[8] = 0;
cdb[7]++;
if (cdb[7] > 59)
{
cdb[7] = 0;
cdb[6]++;
}
}
#ifdef CDROM_DEBUG
printf("multi-frame read: from %d %d %d to %d %d %d skip %ld\n", cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], skip);
#endif
}
rv = cdrom_send_command(fd, DIRECTION_IN, s, len, cdb, sizeof(cdb));
rv = cdrom_send_command(fd, DIRECTION_IN, s, len, cdb, sizeof(cdb), skip);
#ifdef CDROM_DEBUG
printf("read status code %d\n", rv);

View File

@ -70,7 +70,7 @@ int cdrom_write_cue(int fd, char **out_buf, size_t *out_len, char cdrom_drive, u
/* needs 32 bytes for full vendor, product and version */
int cdrom_get_inquiry(int fd, char *model, int len);
int cdrom_read(int fd, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len);
int cdrom_read(int fd, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip);
RETRO_END_DECLS

View File

@ -26,6 +26,36 @@
#include <stdint.h>
#include <libretro.h>
enum vfs_scheme
{
VFS_SCHEME_NONE = 0,
VFS_SCHEME_CDROM
};
#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else
struct libretro_vfs_implementation_file
#endif
{
int fd;
unsigned hints;
int64_t size;
char *buf;
FILE *fp;
char* orig_path;
uint64_t mappos;
uint64_t mapsize;
uint8_t *mapped;
enum vfs_scheme scheme;
#ifdef HAVE_CDROM
char *cdrom_cue_buf;
size_t cdrom_cue_len;
size_t cdrom_byte_pos;
char cdrom_drive;
#endif
};
/* Replace the following symbol with something appropriate
* to signify the file is being compiled for a front end instead of a core.
* This allows the same code to act as reference implementation

View File

@ -0,0 +1,46 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_cdrom.h).
* ---------------------------------------------------------------------------------------
*
* 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.
*/
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
#include <cdrom/cdrom.h>
#include <vfs/vfs_implementation.h>
RETRO_BEGIN_DECLS
int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence);
FILE* retro_vfs_file_open_cdrom(
libretro_vfs_implementation_file *stream,
const char *path, unsigned mode, unsigned hints);
int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream);
int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream);
int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
void *s, uint64_t len);
RETRO_END_DECLS
#endif

View File

@ -158,12 +158,6 @@
#define FIO_S_ISDIR SCE_S_ISDIR
#endif
#if defined(__linux__)
#include <math.h>
#include <stropts.h>
#include <scsi/sg.h>
#endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */
#endif
@ -197,46 +191,11 @@
#include <file/file_path.h>
#ifdef HAVE_CDROM
#include <cdrom/cdrom.h>
#include <vfs/vfs_implementation_cdrom.h>
#endif
#define RFILE_HINT_UNBUFFERED (1 << 8)
enum vfs_scheme
{
VFS_SCHEME_NONE = 0,
VFS_SCHEME_CDROM
};
#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else
struct libretro_vfs_implementation_file
#endif
{
int fd;
unsigned hints;
int64_t size;
char *buf;
FILE *fp;
char* orig_path;
#if defined(HAVE_MMAP)
uint64_t mappos;
uint64_t mapsize;
uint8_t *mapped;
#endif
enum vfs_scheme scheme;
#ifdef HAVE_CDROM
char *cdrom_cue_buf;
size_t cdrom_cue_len;
size_t cdrom_cue_pos;
size_t cdrom_byte_pos;
char cdrom_drive;
#endif
};
static cdrom_toc_t vfs_cdrom_toc = {0};
int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
{
if (!stream)
@ -263,79 +222,7 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
#else
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
{
const char *ext = path_get_extension(stream->orig_path);
if (string_is_equal_noncase(ext, "cue"))
{
switch (whence)
{
case SEEK_SET:
stream->cdrom_cue_pos = offset;
break;
case SEEK_CUR:
stream->cdrom_cue_pos += offset;
break;
case SEEK_END:
stream->cdrom_cue_pos = (stream->cdrom_cue_len - 1) + offset;
break;
}
#ifdef CDROM_DEBUG
printf("CDROM Seek: Path %s Offset %lu is now at %lu\n", stream->orig_path, offset, stream->cdrom_cue_pos);
#endif
}
else if (string_is_equal_noncase(ext, "bin"))
{
unsigned char min = offset / 75 / 60;
unsigned char sec = offset / 75;
unsigned char frame = offset - ((min * 75 * 60) + (sec * 75));
switch (whence)
{
case SEEK_CUR:
{
min += vfs_cdrom_toc.cur_min;
sec += vfs_cdrom_toc.cur_sec;
frame += vfs_cdrom_toc.cur_frame;
stream->cdrom_byte_pos += offset;
break;
}
case SEEK_END:
{
unsigned char end_min = 0;
unsigned char end_sec = 0;
unsigned char end_frame = 0;
size_t end_lba = vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].lba_start + vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].track_size;
lba_to_msf(end_lba, &min, &sec, &frame);
min += end_min;
sec += end_sec;
frame += end_frame;
stream->cdrom_byte_pos = end_lba * 2352;
break;
}
case SEEK_SET:
default:
stream->cdrom_byte_pos = offset;
break;
}
vfs_cdrom_toc.cur_min = min;
vfs_cdrom_toc.cur_sec = sec;
vfs_cdrom_toc.cur_frame = frame;
#ifdef CDROM_DEBUG
printf("CDROM Seek: Path %s Offset %lu is now at %lu\n", stream->orig_path, offset, stream->cdrom_byte_pos);
#endif
}
}
return retro_vfs_file_seek_cdrom(stream, offset, whence);
else
#endif
return fseeko(stream->fp, (off_t)offset, whence);
@ -421,7 +308,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
size_t cdrom_prefix_siz = strlen(cdrom_prefix);
int cdrom_prefix_len = (int)cdrom_prefix_siz;
if (path_len >= cdrom_prefix_len)
if (path_len > cdrom_prefix_len)
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
@ -522,70 +409,10 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
{
#ifdef __linux__
char model[32] = {0};
char cdrom_path[] = "/dev/sg1";
size_t path_len = strlen(path);
const char *ext = path_get_extension(path);
fp = retro_vfs_file_open_cdrom(stream, path, mode, hints);
if (path_len >= strlen("drive1.cue"))
{
if (!memcmp(path, "drive", strlen("drive")))
{
if (path[5] >= '0' && path[5] <= '9')
{
cdrom_path[7] = path[5];
stream->cdrom_drive = path[5];
}
}
}
#ifdef CDROM_DEBUG
printf("CDROM Open: Path %s URI %s\n", cdrom_path, path);
#endif
fp = (FILE*)fopen_utf8(cdrom_path, "r+b");
if (fp)
{
int cdrom_fd = fileno(fp);
if (!cdrom_get_inquiry(cdrom_fd, model, sizeof(model)))
{
size_t len = 0;
#ifdef CDROM_DEBUG
printf("CDROM Model: %s\n", model);
#endif
}
}
else
if (!fp)
goto error;
if (string_is_equal_noncase(ext, "cue"))
{
if (stream->cdrom_cue_buf)
{
free(stream->cdrom_cue_buf);
stream->cdrom_cue_buf = NULL;
}
cdrom_write_cue(fileno(fp), &stream->cdrom_cue_buf, &stream->cdrom_cue_len, stream->cdrom_drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
if (vfs_cdrom_toc.num_tracks > 1)
{
vfs_cdrom_toc.cur_min = vfs_cdrom_toc.track[0].min;
vfs_cdrom_toc.cur_sec = vfs_cdrom_toc.track[0].sec;
vfs_cdrom_toc.cur_frame = vfs_cdrom_toc.track[0].frame;
}
if (string_is_empty(stream->cdrom_cue_buf))
printf("Error writing cue sheet.\n");
#ifdef CDROM_DEBUG
else
printf("CDROM CUE Sheet:\n%s\n", stream->cdrom_cue_buf);
#endif
}
#endif
}
else
#endif
@ -678,7 +505,14 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{
if (stream->fp)
fclose(stream->fp);
{
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
retro_vfs_file_close_cdrom(stream);
else
#endif
fclose(stream->fp);
}
}
else
{
@ -700,13 +534,6 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
if (stream->buf)
free(stream->buf);
#ifdef HAVE_CDROM
#ifdef CDROM_DEBUG
if (stream->scheme == VFS_SCHEME_CDROM)
printf("CDROM Close: Path %s\n", stream->orig_path);
#endif
#endif
if (stream->orig_path)
free(stream->orig_path);
@ -771,30 +598,7 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
#else
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
{
const char *ext = path_get_extension(stream->orig_path);
if (string_is_equal_noncase(ext, "cue"))
{
#ifdef HAVE_CDROM
#ifdef CDROM_DEBUG
printf("CDROM (cue) Tell: Path %s Position %lu\n", stream->orig_path, stream->cdrom_cue_pos);
#endif
#endif
return stream->cdrom_cue_pos;
}
else if (string_is_equal_noncase(ext, "bin"))
{
unsigned lba = msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame);
#ifdef HAVE_CDROM
#ifdef CDROM_DEBUG
printf("CDROM (bin) Tell: Path %s Position %u\n", stream->orig_path, lba * 2352);
#endif
#endif
return lba * 2352;
}
}
return retro_vfs_file_tell_cdrom(stream);
else
#endif
return ftell(stream->fp);
@ -848,60 +652,7 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
#else
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
{
int rv;
const char *ext = path_get_extension(stream->orig_path);
if (string_is_equal_noncase(ext, "cue"))
{
if (len < stream->cdrom_cue_len - stream->cdrom_cue_pos)
{
#ifdef CDROM_DEBUG
printf("CDROM Read: Reading %lu bytes from cuesheet starting at %lu...\n", len, stream->cdrom_cue_pos);
#endif
memcpy(s, stream->cdrom_cue_buf + stream->cdrom_cue_pos, len);
stream->cdrom_cue_pos += len;
}
else
{
#ifdef CDROM_DEBUG
printf("CDROM Read: Reading %lu bytes from cuesheet starting at %lu failed.\n", len, stream->cdrom_cue_pos);
#endif
}
}
else if (string_is_equal_noncase(ext, "bin"))
{
unsigned frames = len / 2352;
unsigned i;
#ifdef CDROM_DEBUG
printf("CDROM Read: Reading %lu bytes from CD starting at byte offset %lu (MSF %02d:%02d:%02d) (LBA %u)...\n", len, stream->cdrom_byte_pos, vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame, msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame));
#endif
rv = cdrom_read(fileno(stream->fp), vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame, s, (size_t)len);
if (rv)
{
#ifdef CDROM_DEBUG
printf("Failed to read %lu bytes from CD.\n", len);
#endif
return 0;
}
stream->cdrom_byte_pos += len;
for (i = 0; i < frames; i++)
{
increment_msf(&vfs_cdrom_toc.cur_min, &vfs_cdrom_toc.cur_sec, &vfs_cdrom_toc.cur_frame);
}
#ifdef CDROM_DEBUG
printf("CDROM read %lu bytes, position is now: %lu (MSF %02d:%02d:%02d) (LBA %u)\n", len, stream->cdrom_byte_pos, vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame, msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame));
#endif
}
return len;
}
return retro_vfs_file_read_cdrom(stream, s, len);
else
#endif
return fread(s, 1, (size_t)len, stream->fp);

View File

@ -0,0 +1,311 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vfs_implementation_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.
*/
#include <vfs/vfs_implementation_cdrom.h>
#include <file/file_path.h>
#include <compat/fopen_utf8.h>
#include <string/stdstring.h>
static cdrom_toc_t vfs_cdrom_toc = {0};
int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence)
{
const char *ext = path_get_extension(stream->orig_path);
if (string_is_equal_noncase(ext, "cue"))
{
switch (whence)
{
case SEEK_SET:
stream->cdrom_byte_pos = offset;
break;
case SEEK_CUR:
stream->cdrom_byte_pos += offset;
break;
case SEEK_END:
stream->cdrom_byte_pos = (stream->cdrom_cue_len - 1) + offset;
break;
}
#ifdef CDROM_DEBUG
printf("CDROM Seek: Path %s Offset %lu is now at %lu\n", stream->orig_path, offset, stream->cdrom_byte_pos);
#endif
}
else if (string_is_equal_noncase(ext, "bin"))
{
unsigned frames = (offset / 2352);
unsigned char min = 0;
unsigned char sec = 0;
unsigned char frame = 0;
const char *seek_type = "SEEK_SET";
lba_to_msf(frames, &min, &sec, &frame);
switch (whence)
{
case SEEK_CUR:
{
min += vfs_cdrom_toc.cur_min;
sec += vfs_cdrom_toc.cur_sec;
frame += vfs_cdrom_toc.cur_frame;
stream->cdrom_byte_pos += offset;
seek_type = "SEEK_CUR";
break;
}
case SEEK_END:
{
unsigned char end_min = 0;
unsigned char end_sec = 0;
unsigned char end_frame = 0;
size_t end_lba = vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].lba_start + vfs_cdrom_toc.track[vfs_cdrom_toc.num_tracks - 1].track_size;
lba_to_msf(end_lba, &min, &sec, &frame);
min += end_min;
sec += end_sec;
frame += end_frame;
stream->cdrom_byte_pos = end_lba * 2352;
seek_type = "SEEK_END";
break;
}
case SEEK_SET:
default:
{
unsigned lba = msf_to_lba(min, sec, frame);
seek_type = "SEEK_SET";
stream->cdrom_byte_pos = offset;
break;
}
}
vfs_cdrom_toc.cur_min = min;
vfs_cdrom_toc.cur_sec = sec;
vfs_cdrom_toc.cur_frame = frame;
#ifdef CDROM_DEBUG
printf("CDROM Seek %s: Path %s Offset %lu is now at %lu (MSF %02d:%02d:%02d) (LBA %u)...\n", seek_type, stream->orig_path, offset, stream->cdrom_byte_pos, vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame, msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame));
#endif
}
else
return -1;
return 0;
}
FILE* retro_vfs_file_open_cdrom(
libretro_vfs_implementation_file *stream,
const char *path, unsigned mode, unsigned hints)
{
FILE *fp = NULL;
#ifdef __linux__
char model[32] = {0};
char cdrom_path[] = "/dev/sg1";
size_t path_len = strlen(path);
const char *ext = path_get_extension(path);
if (!string_is_equal_noncase(ext, "cue") && !string_is_equal_noncase(ext, "bin"))
return NULL;
if (path_len >= strlen("drive1.cue"))
{
if (!memcmp(path, "drive", strlen("drive")))
{
if (path[5] >= '0' && path[5] <= '9')
{
cdrom_path[7] = path[5];
stream->cdrom_drive = path[5];
}
}
}
#ifdef CDROM_DEBUG
printf("CDROM Open: Path %s URI %s\n", cdrom_path, path);
#endif
fp = (FILE*)fopen_utf8(cdrom_path, "r+b");
if (fp)
{
int cdrom_fd = fileno(fp);
if (!cdrom_get_inquiry(cdrom_fd, model, sizeof(model)))
{
size_t len = 0;
#ifdef CDROM_DEBUG
printf("CDROM Model: %s\n", model);
#endif
}
}
else
return NULL;
if (string_is_equal_noncase(ext, "cue"))
{
if (stream->cdrom_cue_buf)
{
free(stream->cdrom_cue_buf);
stream->cdrom_cue_buf = NULL;
}
cdrom_write_cue(fileno(fp), &stream->cdrom_cue_buf, &stream->cdrom_cue_len, stream->cdrom_drive, &vfs_cdrom_toc.num_tracks, &vfs_cdrom_toc);
if (vfs_cdrom_toc.num_tracks > 1)
{
vfs_cdrom_toc.cur_min = vfs_cdrom_toc.track[0].min;
vfs_cdrom_toc.cur_sec = vfs_cdrom_toc.track[0].sec;
vfs_cdrom_toc.cur_frame = vfs_cdrom_toc.track[0].frame;
}
#ifdef CDROM_DEBUG
if (string_is_empty(stream->cdrom_cue_buf))
printf("Error writing cue sheet.\n");
else
{
printf("CDROM CUE Sheet:\n%s\n", stream->cdrom_cue_buf);
fflush(stdout);
}
#endif
}
#endif
return fp;
}
int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)
{
#ifdef CDROM_DEBUG
if (stream->scheme == VFS_SCHEME_CDROM)
printf("CDROM Close: Path %s\n", stream->orig_path);
#endif
if (fclose(stream->fp))
return -1;
return 0;
}
int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
{
if (!stream)
return -1;
const char *ext = path_get_extension(stream->orig_path);
if (string_is_equal_noncase(ext, "cue"))
{
#ifdef CDROM_DEBUG
printf("CDROM (cue) Tell: Path %s Position %lu\n", stream->orig_path, stream->cdrom_byte_pos);
#endif
return stream->cdrom_byte_pos;
}
else if (string_is_equal_noncase(ext, "bin"))
{
unsigned lba = msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame);
#ifdef CDROM_DEBUG
printf("CDROM (bin) Tell: Path %s Position %u\n", stream->orig_path, lba * 2352);
#endif
return lba * 2352;
}
return -1;
}
int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
void *s, uint64_t len)
{
int rv;
const char *ext = path_get_extension(stream->orig_path);
if (string_is_equal_noncase(ext, "cue"))
{
if (len < stream->cdrom_cue_len - stream->cdrom_byte_pos)
{
#ifdef CDROM_DEBUG
printf("CDROM Read: Reading %lu bytes from cuesheet starting at %lu...\n", len, stream->cdrom_byte_pos);
#endif
memcpy(s, stream->cdrom_cue_buf + stream->cdrom_byte_pos, len);
stream->cdrom_byte_pos += len;
return len;
}
else
{
#ifdef CDROM_DEBUG
printf("CDROM Read: Reading %lu bytes from cuesheet starting at %lu failed.\n", len, stream->cdrom_byte_pos);
#endif
return 0;
}
}
else if (string_is_equal_noncase(ext, "bin"))
{
unsigned frames = len / 2352;
unsigned i;
size_t skip = stream->cdrom_byte_pos % 2352;
unsigned char min = 0;
unsigned char sec = 0;
unsigned char frame = 0;
unsigned lba_cur = 0;
unsigned lba_start = 0;
lba_cur = msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame);
lba_start = msf_to_lba(vfs_cdrom_toc.track[0].min, vfs_cdrom_toc.track[0].sec, vfs_cdrom_toc.track[0].frame);
lba_to_msf(lba_start + lba_cur, &min, &sec, &frame);
#ifdef CDROM_DEBUG
printf("CDROM Read: Reading %lu bytes from %s starting at byte offset %lu (MSF %02d:%02d:%02d) (LBA %u) skip %lu...\n", len, stream->orig_path, stream->cdrom_byte_pos, min, sec, frame, msf_to_lba(min, sec, frame), skip);
#endif
rv = cdrom_read(fileno(stream->fp), min, sec, frame, s, (size_t)len, skip);
if (rv)
{
#ifdef CDROM_DEBUG
printf("Failed to read %lu bytes from CD.\n", len);
#endif
return 0;
}
stream->cdrom_byte_pos += len;
for (i = 0; i < frames; i++)
{
increment_msf(&vfs_cdrom_toc.cur_min, &vfs_cdrom_toc.cur_sec, &vfs_cdrom_toc.cur_frame);
}
#ifdef CDROM_DEBUG
printf("CDROM read %lu bytes, position is now: %lu (MSF %02d:%02d:%02d) (LBA %u)\n", len, stream->cdrom_byte_pos, vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame, msf_to_lba(vfs_cdrom_toc.cur_min, vfs_cdrom_toc.cur_sec, vfs_cdrom_toc.cur_frame));
#endif
return len;
}
return 0;
}