pcsxr/plugins/dfcdrom/cdr-libcdio.c

258 lines
5.4 KiB
C

/*
* Copyright (c) 2010, Wei Mingzhi <whistler@openoffice.org>.
* All Rights Reserved.
*
* Based on: Cdrom for Psemu Pro like Emulators
* By: linuzappz <linuzappz@hotmail.com>
*
* 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
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
#ifdef USE_LIBCDIO
#include "cdr.h"
#include <cdio/cdio.h>
#include <cdio/mmc.h>
static CdIo_t *cdHandle = NULL;
static void SetSpeed(int speed) {
speed *= 176;
if (speed == 0) speed = 0xFFFF;
cdio_set_speed(cdHandle, speed);
}
static void SetSpinDown(unsigned char spindown) {
mmc_cdb_t cdb;
char buf[16];
memset(&cdb, 0, sizeof(cdb));
cdb.field[0] = 0x5A;
cdb.field[2] = 0x0D;
cdb.field[8] = sizeof(buf);
if (mmc_run_cmd(cdHandle, 10000, &cdb, SCSI_MMC_DATA_READ, sizeof(buf), buf) != DRIVER_OP_SUCCESS)
return;
buf[11] = (buf[11] & 0xF0) | (spindown & 0x0F);
memset(&cdb, 0, sizeof(cdb));
memset(buf, 0, 2);
cdb.field[0] = 0x55;
cdb.field[1] = 0x10;
cdb.field[8] = sizeof(buf);
mmc_run_cmd(cdHandle, 10000, &cdb, SCSI_MMC_DATA_WRITE, sizeof(buf), buf);
}
static void UnlockDoor() {
mmc_cdb_t cdb;
memset(&cdb, 0, sizeof(cdb));
cdb.field[0] = 0x1E;
cdb.field[4] = 0;
mmc_run_cmd(cdHandle, 10000, &cdb, SCSI_MMC_DATA_WRITE, 0, NULL);
}
int OpenCdHandle(const char *dev) {
if (dev == NULL || dev[0] == '\0') {
if ((dev = cdio_get_default_device(NULL)) == NULL) {
return -1;
}
}
#ifdef __FreeBSD__
cdHandle = cdio_open_am_cd(dev, "CAM");
#else
cdHandle = cdio_open_cd(dev);
#endif
if (cdHandle != NULL) {
SetSpeed(CdrSpeed);
SetSpinDown(SpinDown);
UnlockDoor();
return 0;
}
return -1;
}
void CloseCdHandle() {
if (cdHandle != NULL) {
cdio_set_speed(cdHandle, 0xFFFF);
SetSpinDown(SPINDOWN_VENDOR_SPECIFIC);
cdio_destroy(cdHandle);
}
cdHandle = NULL;
}
int IsCdHandleOpen() {
return (cdHandle != NULL);
}
long GetTN(unsigned char *buffer) {
buffer[0] = cdio_get_first_track_num(cdHandle);
buffer[1] = cdio_get_last_track_num(cdHandle);
return 0;
}
long GetTD(unsigned char track, unsigned char *buffer) {
msf_t msf;
if (track == 0) track = CDIO_CDROM_LEADOUT_TRACK;
if (!cdio_get_track_msf(cdHandle, track, &msf)) {
memset(buffer + 1, 0, 3);
return 0;
}
buffer[0] = btoi(msf.f);
buffer[1] = btoi(msf.s);
buffer[2] = btoi(msf.m);
return 0;
}
long GetTE(unsigned char track, unsigned char *m, unsigned char *s, unsigned char *f) {
unsigned char msf[3];
lba_to_msf(cdio_get_track_lba(cdHandle, track + 1) - CD_MSF_OFFSET, msf);
*m = msf[0];
*s = msf[1];
*f = msf[2];
return 0;
}
long ReadSector(crdata *cr) {
int lba;
MMC_READ_CD cdb;
lba = msf_to_lba(cr->msf.cdmsf_min0, cr->msf.cdmsf_sec0, cr->msf.cdmsf_frame0);
memset(&cdb, 0, sizeof(cdb));
cdb.Code = 0xBE;
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 (mmc_run_cmd(cdHandle, 10000, (mmc_cdb_t *)&cdb, SCSI_MMC_DATA_READ, sizeof(*cr), cr) != DRIVER_OP_SUCCESS)
return -1;
return 0;
}
long PlayCDDA(unsigned char *sector) {
msf_t start, end;
if (!cdio_get_track_msf(cdHandle, CDIO_CDROM_LEADOUT_TRACK, &end))
return -1;
start.m = itob(sector[0]);
start.s = itob(sector[1]);
start.f = itob(sector[2]);
if (cdio_audio_play_msf(cdHandle, &start, &end) != DRIVER_OP_SUCCESS)
return -1;
return 0;
}
long StopCDDA() {
cdio_subchannel_t subchnl;
if (cdio_audio_read_subchannel(cdHandle, &subchnl) != DRIVER_OP_SUCCESS)
return -1;
switch (subchnl.audio_status) {
case CDIO_MMC_READ_SUB_ST_PLAY:
case CDIO_MMC_READ_SUB_ST_PAUSED:
cdio_audio_stop(cdHandle);
}
return 0;
}
long GetStatus(int playing, struct CdrStat *stat) {
cdio_subchannel_t subchnl;
memset(stat, 0, sizeof(struct CdrStat));
if (playing) {
if (cdio_audio_read_subchannel(cdHandle, &subchnl) == DRIVER_OP_SUCCESS) {
stat->Time[0] = btoi(subchnl.abs_addr.m);
stat->Time[1] = btoi(subchnl.abs_addr.s);
stat->Time[2] = btoi(subchnl.abs_addr.f);
}
}
stat->Type = 0x01;
if (mmc_get_tray_status(cdHandle)) {
stat->Type = 0xff;
stat->Status |= 0x10;
} else {
SetSpeed(CdrSpeed);
SetSpinDown(SpinDown);
UnlockDoor();
}
return 0;
}
unsigned char *ReadSub(const unsigned char *time) {
int lba = msf_to_lba(btoi(time[0]), btoi(time[1]), btoi(time[2]));
static unsigned char buf[CD_FRAMESIZE_RAW + 96];
MMC_READ_CD cdb;
memset(&cdb, 0, sizeof(cdb));
cdb.Code = 0xBE;
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 (mmc_run_cmd(cdHandle, 10000, (mmc_cdb_t *)&cdb, SCSI_MMC_DATA_READ, sizeof(buf), buf) != DRIVER_OP_SUCCESS)
return NULL;
DecodeRawSubData(buf + CD_FRAMESIZE_RAW);
return buf + CD_FRAMESIZE_RAW;
}
#endif