/* * Copyright (c) 2010, Wei Mingzhi . * All Rights Reserved. * * Based on: Cdrom for Psemu Pro like Emulators * By: linuzappz * * 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 . */ #ifdef USE_LIBCDIO #include #include #include "cdr.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