summaryrefslogtreecommitdiff
path: root/plugins/dfcdrom/cdr-linux.c
diff options
context:
space:
mode:
authorSND\weimingzhi_cp <SND\weimingzhi_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2010-07-10 06:54:11 +0000
committerSND\weimingzhi_cp <SND\weimingzhi_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2010-07-10 06:54:11 +0000
commitf7823bc1646f1885bd9a0a19a9645c0e2cb884bd (patch)
tree15f115383205088b3fca3f4c41a319e1da183ac7 /plugins/dfcdrom/cdr-linux.c
parentfcf4fb0933140db08c7bc094abc9edb271c13359 (diff)
downloadpcsxr-f7823bc1646f1885bd9a0a19a9645c0e2cb884bd.tar.gz
I was really stupid... just use libcdio and everything's fine, no need to deal with different OSes at all.
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@54442 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'plugins/dfcdrom/cdr-linux.c')
-rw-r--r--plugins/dfcdrom/cdr-linux.c249
1 files changed, 208 insertions, 41 deletions
diff --git a/plugins/dfcdrom/cdr-linux.c b/plugins/dfcdrom/cdr-linux.c
index 3d15c4d2..2c598076 100644
--- a/plugins/dfcdrom/cdr-linux.c
+++ b/plugins/dfcdrom/cdr-linux.c
@@ -5,6 +5,9 @@
* Based on: Cdrom for Psemu Pro like Emulators
* By: linuzappz <linuzappz@hotmail.com>
*
+ * Portions based on: cdrdao - write audio CD-Rs in disc-at-once mode
+ * Copyright (C) 2007 Denis Leroy <denis@poolshark.org>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -19,49 +22,135 @@
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
-#include "cdr.h"
+#if defined (__linux__) && !defined (USE_LIBCDIO)
-#ifdef __linux__
+#include "cdr.h"
char *LibName = N_("CD-ROM Drive Reader");
-static int handle = -1;
+static int cdHandle = -1;
+static int ReadMMC = 0, SubQMMC = 0;
+
+static int SendMMCCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut,
+ int dataOutLen, unsigned char *dataIn, int dataInLen)
+{
+ sg_io_hdr_t io_hdr;
+
+ memset(&io_hdr, 0, sizeof(io_hdr));
+
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = cmdLen;
+ io_hdr.cmdp = (unsigned char *)cmd;
+ io_hdr.timeout = 10000;
+ io_hdr.sbp = NULL;
+ io_hdr.mx_sb_len = 0;
+ io_hdr.flags = 1;
+
+ if (dataOut != NULL) {
+ io_hdr.dxferp = (void *)dataOut;
+ io_hdr.dxfer_len = dataOutLen;
+ io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ } else if (dataIn != NULL) {
+ io_hdr.dxferp = (void *)dataIn;
+ io_hdr.dxfer_len = dataInLen;
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ }
+
+ if (ioctl(cdHandle, SG_IO, &io_hdr) < 0) {
+ return -1;
+ }
+
+ return io_hdr.status;
+}
+
+static int CheckReadMMC() {
+ MMC_READ_CD cdb;
+ unsigned char buf[CD_FRAMESIZE_RAW];
+
+ memset(&cdb, 0, sizeof(cdb));
+ memset(buf, 0xAA, sizeof(buf));
+
+ cdb.Code = GPCMD_READ_CD;
+ cdb.IncludeEDC = 0;
+ cdb.IncludeUserData = 1;
+ cdb.HeaderCode = 3;
+ cdb.IncludeSyncData = 1;
+ cdb.TransferBlocks[2] = 1;
+
+ if (SendMMCCmd((unsigned char *)&cdb, sizeof(cdb), NULL, 0, buf, sizeof(buf)) == 0) {
+ if (buf[0] != 0xAA) {
+ PRINTF("Using MMC for data\n");
+ return 1; // supported
+ }
+ }
+
+ return 0; // NOT supported
+}
+
+static int CheckSubQMMC() {
+ MMC_READ_CD cdb;
+ unsigned char buf[CD_FRAMESIZE_RAW + 96];
+
+ memset(&cdb, 0, sizeof(cdb));
+ memset(buf, 0xAA, sizeof(buf));
+
+ cdb.Code = GPCMD_READ_CD;
+ cdb.IncludeEDC = 1;
+ cdb.IncludeUserData = 1;
+ cdb.HeaderCode = 3;
+ cdb.IncludeSyncData = 1;
+ cdb.SubChannelSelection = 1;
+ cdb.TransferBlocks[2] = 1;
+
+ if (SendMMCCmd((unsigned char *)&cdb, sizeof(cdb), NULL, 0, buf, sizeof(buf)) == 0) {
+ if (buf[0] != 0xAA && (buf[2352] != 0xAA || buf[2353] != 0xAA)) {
+ PRINTF("Using MMC for subchannel\n");
+ return 1; // supported
+ }
+ }
+
+ return 0; // NOT supported
+}
int OpenCdHandle(const char *dev) {
char spindown;
- handle = open(dev, O_RDONLY);
+ cdHandle = open(dev, O_RDONLY);
- if (handle != -1) {
- ioctl(handle, CDROM_LOCKDOOR, 0);
-// ioctl(handle, CDROMSTART, NULL);
+ if (cdHandle != -1) {
+ ioctl(cdHandle, CDROM_LOCKDOOR, 0);
spindown = (char)SpinDown;
- ioctl(handle, CDROMSETSPINDOWN, &spindown);
+ ioctl(cdHandle, CDROMSETSPINDOWN, &spindown);
+
+ ioctl(cdHandle, CDROM_SELECT_SPEED, CdrSpeed);
- ioctl(handle, CDROM_SELECT_SPEED, CdrSpeed);
+ ReadMMC = CheckReadMMC();
+ SubQMMC = CheckSubQMMC();
+
+ return 0;
}
- return (handle == -1) ? -1 : 0;
+ return -1;
}
void CloseCdHandle() {
char spindown = SPINDOWN_VENDOR_SPECIFIC;
- ioctl(handle, CDROMSETSPINDOWN, &spindown);
+ ioctl(cdHandle, CDROMSETSPINDOWN, &spindown);
- close(handle);
+ close(cdHandle);
- handle = -1;
+ cdHandle = -1;
}
int IsCdHandleOpen() {
- return (handle != -1);
+ return (cdHandle != -1);
}
long GetTN(unsigned char *buffer) {
struct cdrom_tochdr toc;
- if (ioctl(handle, CDROMREADTOCHDR, &toc) == -1)
+ if (ioctl(cdHandle, CDROMREADTOCHDR, &toc) == -1)
return -1;
buffer[0] = toc.cdth_trk0; // start track
@@ -74,28 +163,32 @@ long GetTD(unsigned char track, unsigned char *buffer) {
struct cdrom_tocentry entry;
if (track == 0)
- track = 0xaa; // total time
+ track = 0xAA; // total time (leadout)
entry.cdte_track = track;
entry.cdte_format = CDROM_MSF;
- if (ioctl(handle, CDROMREADTOCENTRY, &entry) == -1)
+ if (ioctl(cdHandle, CDROMREADTOCENTRY, &entry) == -1)
return -1;
- buffer[0] = entry.cdte_addr.msf.frame; /* frame */
- buffer[1] = entry.cdte_addr.msf.second; /* second */
- buffer[2] = entry.cdte_addr.msf.minute; /* minute */
+ buffer[0] = entry.cdte_addr.msf.frame;
+ buffer[1] = entry.cdte_addr.msf.second;
+ buffer[2] = entry.cdte_addr.msf.minute;
return 0;
}
long GetTE(unsigned char track, unsigned char *m, unsigned char *s, unsigned char *f) {
struct cdrom_tocentry entry;
- char msf[3];
+ unsigned char msf[3];
+
+ if (GetTN(msf) == -1) return -1;
entry.cdte_track = track + 1;
+ if (entry.cdte_track > msf[1]) entry.cdte_track = 0xaa;
+
entry.cdte_format = CDROM_MSF;
- if (ioctl(handle, CDROMREADTOCENTRY, &entry) == -1)
+ if (ioctl(cdHandle, CDROMREADTOCENTRY, &entry) == -1)
return -1;
lba_to_msf(msf_to_lba(entry.cdte_addr.msf.minute, entry.cdte_addr.msf.second, entry.cdte_addr.msf.frame) - CD_MSF_OFFSET, msf);
@@ -108,8 +201,31 @@ long GetTE(unsigned char track, unsigned char *m, unsigned char *s, unsigned cha
}
long ReadSector(crdata *cr) {
- if (ioctl(handle, CDROMREADRAW, cr) == -1)
- return -1;
+ if (ReadMMC) {
+ MMC_READ_CD cdb;
+ int lba;
+
+ memset(&cdb, 0, sizeof(cdb));
+
+ lba = msf_to_lba(cr->msf.cdmsf_min0, cr->msf.cdmsf_sec0, cr->msf.cdmsf_frame0);
+
+ cdb.Code = GPCMD_READ_CD;
+ cdb.IncludeEDC = 1;
+ cdb.IncludeUserData = 1;
+ cdb.HeaderCode = 3;
+ cdb.IncludeSyncData = 1;
+ cdb.SubChannelSelection = 0;
+ cdb.StartingLBA[1] = lba >> 16;
+ cdb.StartingLBA[2] = lba >> 8;
+ cdb.StartingLBA[3] = lba;
+ cdb.TransferBlocks[2] = 1;
+
+ if (SendMMCCmd((unsigned char *)&cdb, sizeof(cdb), NULL, 0, (unsigned char *)cr, sizeof(*cr)) != 0)
+ return -1;
+ } else {
+ if (ioctl(cdHandle, CDROMREADRAW, cr) == -1)
+ return -1;
+ }
return 0;
}
@@ -129,7 +245,7 @@ long PlayCDDA(unsigned char *sector) {
addr.cdmsf_sec1 = ptmp[1];
addr.cdmsf_frame1 = ptmp[0];
- if (ioctl(handle, CDROMPLAYMSF, &addr) == -1)
+ if (ioctl(cdHandle, CDROMPLAYMSF, &addr) == -1)
return -1;
return 0;
@@ -139,13 +255,13 @@ long StopCDDA() {
struct cdrom_subchnl sc;
sc.cdsc_format = CDROM_MSF;
- if (ioctl(handle, CDROMSUBCHNL, &sc) == -1)
+ if (ioctl(cdHandle, CDROMSUBCHNL, &sc) == -1)
return -1;
switch (sc.cdsc_audiostatus) {
case CDROM_AUDIO_PAUSED:
case CDROM_AUDIO_PLAY:
- ioctl(handle, CDROMSTOP);
+ ioctl(cdHandle, CDROMSTOP);
break;
}
@@ -161,11 +277,11 @@ long GetStatus(int playing, struct CdrStat *stat) {
if (playing) { // return Time only if playing
sc.cdsc_format = CDROM_MSF;
- if (ioctl(handle, CDROMSUBCHNL, &sc) != -1)
+ if (ioctl(cdHandle, CDROMSUBCHNL, &sc) != -1)
memcpy(stat->Time, &sc.cdsc_absaddr.msf, 3);
}
- ret = ioctl(handle, CDROM_DISC_STATUS);
+ ret = ioctl(cdHandle, CDROM_DISC_STATUS);
switch (ret) {
case CDS_AUDIO:
stat->Type = 0x02;
@@ -177,7 +293,7 @@ long GetStatus(int playing, struct CdrStat *stat) {
stat->Type = 0x01;
break;
}
- ret = ioctl(handle, CDROM_DRIVE_STATUS);
+ ret = ioctl(cdHandle, CDROM_DRIVE_STATUS);
switch (ret) {
case CDS_NO_DISC:
case CDS_TRAY_OPEN:
@@ -186,8 +302,9 @@ long GetStatus(int playing, struct CdrStat *stat) {
break;
default:
spindown = (char)SpinDown;
- ioctl(handle, CDROMSETSPINDOWN, &spindown);
- ioctl(handle, CDROM_LOCKDOOR, 0);
+ ioctl(cdHandle, CDROMSETSPINDOWN, &spindown);
+ ioctl(cdHandle, CDROM_SELECT_SPEED, CdrSpeed);
+ ioctl(cdHandle, CDROM_LOCKDOOR, 0);
break;
}
@@ -200,28 +317,55 @@ long GetStatus(int playing, struct CdrStat *stat) {
return 0;
}
-unsigned char *ReadSub(const unsigned char *time) {
+static unsigned char *ReadSubMMC(const unsigned char *time) {
+ static unsigned char buf[CD_FRAMESIZE_RAW + 96];
+ int lba = msf_to_lba(btoi(time[0]), btoi(time[1]), btoi(time[2]));
+ MMC_READ_CD cdb;
+
+ memset(&cdb, 0, sizeof(cdb));
+
+ cdb.Code = GPCMD_READ_CD;
+ cdb.IncludeEDC = 1;
+ cdb.IncludeUserData = 1;
+ cdb.HeaderCode = 3;
+ cdb.IncludeSyncData = 1;
+ cdb.StartingLBA[1] = lba >> 16;
+ cdb.StartingLBA[2] = lba >> 8;
+ cdb.StartingLBA[3] = lba;
+ cdb.TransferBlocks[2] = 1;
+ cdb.SubChannelSelection = 1;
+
+ if (SendMMCCmd((unsigned char *)&cdb, sizeof(cdb), NULL, 0, buf, sizeof(buf)) != 0)
+ return NULL;
+
+ DecodeRawSubData(buf + CD_FRAMESIZE_RAW);
+ return buf + CD_FRAMESIZE_RAW;
+}
+
+static unsigned char *ReadSubIOCTL(const unsigned char *time) {
static struct SubQ subq;
struct cdrom_subchnl subchnl;
- int ret;
+ int r;
crdata cr;
+ unsigned short crc;
cr.msf.cdmsf_min0 = btoi(time[0]);
cr.msf.cdmsf_sec0 = btoi(time[1]);
cr.msf.cdmsf_frame0 = btoi(time[2]);
- if (ioctl(handle, CDROMSEEK, &cr.msf) == -1) {
+ if (ioctl(cdHandle, CDROMSEEK, &cr.msf) == -1) {
// will be slower, but there's no other way to make it accurate
- if (ioctl(handle, CDROMREADRAW, &cr) == -1) {
+ if (ioctl(cdHandle, CDROMREADRAW, &cr) == -1) {
return NULL;
}
}
subchnl.cdsc_format = CDROM_MSF;
- ret = ioctl(handle, CDROMSUBCHNL, &subchnl);
+ r = ioctl(cdHandle, CDROMSUBCHNL, &subchnl);
- if (ret == -1) return NULL;
+ if (r == -1) return NULL;
+ subq.ControlAndADR = 0x41;
subq.TrackNumber = subchnl.cdsc_trk;
subq.IndexNumber = subchnl.cdsc_ind;
subq.TrackRelativeAddress[0] = itob(subchnl.cdsc_reladdr.msf.minute);
@@ -231,12 +375,35 @@ unsigned char *ReadSub(const unsigned char *time) {
subq.AbsoluteAddress[1] = itob(subchnl.cdsc_absaddr.msf.second);
subq.AbsoluteAddress[2] = itob(subchnl.cdsc_absaddr.msf.frame);
+ // CRC is not supported with IOCTL, fake it.
+ crc = calcCrc((unsigned char *)&subq + 12, 10);
+ subq.CRC[0] = (crc >> 8);
+ subq.CRC[1] = (crc & 0xFF);
+
+ r = msf_to_lba(btoi(time[0]), btoi(time[1]), btoi(time[2]));
+
+ if (GetTE(1, &cr.msf.cdmsf_min0, &cr.msf.cdmsf_sec0, &cr.msf.cdmsf_frame0) == -1) {
+ cr.msf.cdmsf_min0 = 80;
+ cr.msf.cdmsf_sec0 = 0;
+ cr.msf.cdmsf_frame0 = 0;
+ }
+
+ if (msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0) >= r &&
+ (msf_to_lba(subchnl.cdsc_absaddr.msf.minute, subchnl.cdsc_absaddr.msf.second, subchnl.cdsc_absaddr.msf.frame) != r ||
+ msf_to_lba(subchnl.cdsc_reladdr.msf.minute, subchnl.cdsc_reladdr.msf.second, subchnl.cdsc_reladdr.msf.frame) != r - CD_MSF_OFFSET))
+ subq.CRC[1] ^= 1; // time mismatch; report wrong CRC
+
PRINTF("subq : %x,%x : %x,%x,%x : %x,%x,%x\n",
- subchnl.cdsc_trk, subchnl.cdsc_ind,
- itob(subchnl.cdsc_reladdr.msf.minute), itob(subchnl.cdsc_reladdr.msf.second), itob(subchnl.cdsc_reladdr.msf.frame),
- itob(subchnl.cdsc_absaddr.msf.minute), itob(subchnl.cdsc_absaddr.msf.second), itob(subchnl.cdsc_absaddr.msf.frame));
+ subchnl.cdsc_trk, subchnl.cdsc_ind,
+ itob(subchnl.cdsc_reladdr.msf.minute), itob(subchnl.cdsc_reladdr.msf.second), itob(subchnl.cdsc_reladdr.msf.frame),
+ itob(subchnl.cdsc_absaddr.msf.minute), itob(subchnl.cdsc_absaddr.msf.second), itob(subchnl.cdsc_absaddr.msf.frame));
return (unsigned char *)&subq;
}
+unsigned char *ReadSub(const unsigned char *time) {
+ if (SubQMMC) return ReadSubMMC(time);
+ else return ReadSubIOCTL(time);
+}
+
#endif