812 lines
27 KiB
C
812 lines
27 KiB
C
/*Win32 CD-ROM support via IOCTL*/
|
|
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#ifdef __MINGW64_VERSION_MAJOR
|
|
#include "ntddcdrm.h"
|
|
#include "ntddscsi.h"
|
|
#else
|
|
#include "ddk/ntddcdrm.h"
|
|
#include "ddk/ntddscsi.h"
|
|
#endif
|
|
#include "ibm.h"
|
|
#include "ide.h"
|
|
#include "cdrom-ioctl.h"
|
|
|
|
int cdrom_drive;
|
|
int old_cdrom_drive;
|
|
|
|
#ifndef __MINGW64_VERSION_MAJOR
|
|
typedef struct _CDROM_TOC_SESSION_DATA {
|
|
UCHAR Length[2];
|
|
UCHAR FirstCompleteSession;
|
|
UCHAR LastCompleteSession;
|
|
TRACK_DATA TrackData[1];
|
|
} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA;
|
|
#endif
|
|
|
|
static ATAPI ioctl_atapi;
|
|
|
|
static uint32_t last_block = 0;
|
|
static uint32_t cdrom_capacity = 0;
|
|
static char ioctl_path[8];
|
|
void ioctl_close(void);
|
|
static HANDLE hIOCTL;
|
|
static CDROM_TOC toc;
|
|
static int tocvalid = 0;
|
|
|
|
#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f)
|
|
|
|
enum
|
|
{
|
|
CD_STOPPED = 0,
|
|
CD_PLAYING,
|
|
CD_PAUSED
|
|
};
|
|
|
|
static int ioctl_cd_state = CD_STOPPED;
|
|
static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0;
|
|
|
|
#define BUF_SIZE 32768
|
|
static int16_t cd_buffer[BUF_SIZE];
|
|
static int cd_buflen = 0;
|
|
void ioctl_audio_callback(int16_t *output, int len)
|
|
{
|
|
RAW_READ_INFO in;
|
|
DWORD count;
|
|
|
|
// return;
|
|
// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount());
|
|
if (ioctl_cd_state != CD_PLAYING)
|
|
return;
|
|
while (cd_buflen < len)
|
|
{
|
|
if (ioctl_cd_pos < ioctl_cd_end)
|
|
{
|
|
in.DiskOffset.LowPart = (ioctl_cd_pos - 150) * 2048;
|
|
in.DiskOffset.HighPart = 0;
|
|
in.SectorCount = 1;
|
|
in.TrackMode = CDDA;
|
|
ioctl_open(0);
|
|
// pclog("Read to %i\n", cd_buflen);
|
|
if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL))
|
|
{
|
|
// pclog("DeviceIoControl returned false\n");
|
|
memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
|
|
ioctl_cd_state = CD_STOPPED;
|
|
cd_buflen = len;
|
|
}
|
|
else
|
|
{
|
|
// pclog("DeviceIoControl returned true\n");
|
|
ioctl_cd_pos++;
|
|
cd_buflen += (2352 / 2);
|
|
}
|
|
ioctl_close();
|
|
}
|
|
else
|
|
{
|
|
memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
|
|
ioctl_cd_state = CD_STOPPED;
|
|
cd_buflen = len;
|
|
}
|
|
}
|
|
memcpy(output, cd_buffer, len * 2);
|
|
// for (c = 0; c < BUF_SIZE - len; c++)
|
|
// cd_buffer[c] = cd_buffer[c + cd_buflen];
|
|
memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2);
|
|
cd_buflen -= len;
|
|
// pclog("Done %i\n", GetTickCount());
|
|
}
|
|
|
|
void ioctl_audio_stop()
|
|
{
|
|
ioctl_cd_state = CD_STOPPED;
|
|
}
|
|
|
|
static int get_track_nr(uint32_t pos)
|
|
{
|
|
int c;
|
|
int track = 0;
|
|
|
|
if (!tocvalid)
|
|
return 0;
|
|
|
|
for (c = toc.FirstTrack; c < toc.LastTrack; c++)
|
|
{
|
|
uint32_t track_address = toc.TrackData[c].Address[3] +
|
|
(toc.TrackData[c].Address[2] * 75) +
|
|
(toc.TrackData[c].Address[1] * 75 * 60);
|
|
|
|
if (track_address <= pos)
|
|
track = c;
|
|
}
|
|
return track;
|
|
}
|
|
|
|
static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf)
|
|
{
|
|
if (!cdrom_drive) return;
|
|
pclog("Play audio - %08X %08X %i\n", pos, len, ismsf);
|
|
if (ismsf)
|
|
{
|
|
int m = (pos >> 16) & 0xff;
|
|
int s = (pos >> 8) & 0xff;
|
|
int f = pos & 0xff;
|
|
pos = MSFtoLBA(m, s, f);
|
|
m = (len >> 16) & 0xff;
|
|
s = (len >> 8) & 0xff;
|
|
f = len & 0xff;
|
|
len = MSFtoLBA(m, s, f);
|
|
pclog("MSF - pos = %08X len = %08X\n", pos, len);
|
|
}
|
|
else
|
|
len += pos;
|
|
ioctl_cd_pos = pos;// + 150;
|
|
ioctl_cd_end = len;// + 150;
|
|
ioctl_cd_state = CD_PLAYING;
|
|
if (ioctl_cd_pos < 150)
|
|
ioctl_cd_pos = 150;
|
|
pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len);
|
|
/* CDROM_PLAY_AUDIO_MSF msf;
|
|
long size;
|
|
BOOL b;
|
|
if (ismsf)
|
|
{
|
|
msf.StartingF=pos&0xFF;
|
|
msf.StartingS=(pos>>8)&0xFF;
|
|
msf.StartingM=(pos>>16)&0xFF;
|
|
msf.EndingF=len&0xFF;
|
|
msf.EndingS=(len>>8)&0xFF;
|
|
msf.EndingM=(len>>16)&0xFF;
|
|
}
|
|
else
|
|
{
|
|
msf.StartingF=(uint8_t)(addr%75); addr/=75;
|
|
msf.StartingS=(uint8_t)(addr%60); addr/=60;
|
|
msf.StartingM=(uint8_t)(addr);
|
|
addr=pos+len+150;
|
|
msf.EndingF=(uint8_t)(addr%75); addr/=75;
|
|
msf.EndingS=(uint8_t)(addr%60); addr/=60;
|
|
msf.EndingM=(uint8_t)(addr);
|
|
}
|
|
ioctl_open(0);
|
|
b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
|
|
pclog("DeviceIoControl returns %i\n", (int) b);
|
|
ioctl_close();*/
|
|
}
|
|
|
|
static void ioctl_pause(void)
|
|
{
|
|
if (!cdrom_drive) return;
|
|
if (ioctl_cd_state == CD_PLAYING)
|
|
ioctl_cd_state = CD_PAUSED;
|
|
// ioctl_open(0);
|
|
// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL);
|
|
// ioctl_close();
|
|
}
|
|
|
|
static void ioctl_resume(void)
|
|
{
|
|
if (!cdrom_drive) return;
|
|
if (ioctl_cd_state == CD_PAUSED)
|
|
ioctl_cd_state = CD_PLAYING;
|
|
// ioctl_open(0);
|
|
// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL);
|
|
// ioctl_close();
|
|
}
|
|
|
|
static void ioctl_stop(void)
|
|
{
|
|
if (!cdrom_drive) return;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
// ioctl_open(0);
|
|
// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL);
|
|
// ioctl_close();
|
|
}
|
|
|
|
static void ioctl_seek(uint32_t pos)
|
|
{
|
|
if (!cdrom_drive) return;
|
|
// ioctl_cd_state = CD_STOPPED;
|
|
pclog("Seek %08X\n", pos);
|
|
ioctl_cd_pos = pos;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
/* pos+=150;
|
|
CDROM_SEEK_AUDIO_MSF msf;
|
|
msf.F=(uint8_t)(pos%75); pos/=75;
|
|
msf.S=(uint8_t)(pos%60); pos/=60;
|
|
msf.M=(uint8_t)(pos);
|
|
// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F);
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
|
|
ioctl_close();*/
|
|
}
|
|
|
|
static int ioctl_ready(void)
|
|
{
|
|
long size;
|
|
int temp;
|
|
CDROM_TOC ltoc;
|
|
// pclog("Ready? %i\n",cdrom_drive);
|
|
if (!cdrom_drive) return 0;
|
|
ioctl_open(0);
|
|
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
if (!temp)
|
|
return 0;
|
|
//pclog("ioctl_ready(): Drive opened successfully\n");
|
|
//if ((cdrom_drive != old_cdrom_drive)) pclog("Drive has changed\n");
|
|
if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) ||
|
|
(ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) ||
|
|
(ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) ||
|
|
!tocvalid || (cdrom_drive != old_cdrom_drive))
|
|
{
|
|
//pclog("ioctl_ready(): Disc or drive changed\n");
|
|
ioctl_cd_state = CD_STOPPED;
|
|
/* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3],
|
|
toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/
|
|
// atapi_discchanged();
|
|
/* ioctl_open(0);
|
|
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
|
|
ioctl_close();*/
|
|
if (cdrom_drive != old_cdrom_drive)
|
|
old_cdrom_drive = cdrom_drive;
|
|
return 1;
|
|
}
|
|
// pclog("IOCTL says ready\n");
|
|
// pclog("ioctl_ready(): All is good\n");
|
|
return 1;
|
|
}
|
|
|
|
static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single)
|
|
{
|
|
long size;
|
|
int c;
|
|
CDROM_TOC lbtoc;
|
|
int lb=0;
|
|
|
|
if (!cdrom_drive) return 0;
|
|
|
|
ioctl_cd_state = CD_STOPPED;
|
|
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&lbtoc,sizeof(lbtoc),(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
tocvalid = 1;
|
|
for (c = 0; c <= lbtoc.LastTrack; c++)
|
|
{
|
|
uint32_t address;
|
|
address = MSFtoLBA(toc.TrackData[c].Address[1], toc.TrackData[c].Address[2], toc.TrackData[c].Address[3]);
|
|
if (address > lb)
|
|
lb = address;
|
|
}
|
|
return lb;
|
|
}
|
|
|
|
static int ioctl_medium_changed(void)
|
|
{
|
|
long size;
|
|
int temp;
|
|
CDROM_TOC ltoc;
|
|
if (!cdrom_drive) return 0; /* This will be handled by the not ready handler instead. */
|
|
ioctl_open(0);
|
|
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
if (!temp)
|
|
return 0; /* Drive empty, a not ready handler matter, not disc change. */
|
|
if (!tocvalid || (cdrom_drive != old_cdrom_drive))
|
|
{
|
|
ioctl_cd_state = CD_STOPPED;
|
|
toc = ltoc;
|
|
tocvalid = 1;
|
|
if (cdrom_drive != old_cdrom_drive)
|
|
old_cdrom_drive = cdrom_drive;
|
|
cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0);
|
|
return 0;
|
|
}
|
|
if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) ||
|
|
(ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) ||
|
|
(ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]))
|
|
{
|
|
ioctl_cd_state = CD_STOPPED;
|
|
toc = ltoc;
|
|
cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0);
|
|
return 1; /* TOC mismatches. */
|
|
}
|
|
return 0; /* None of the above, return 0. */
|
|
}
|
|
|
|
static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf)
|
|
{
|
|
CDROM_SUB_Q_DATA_FORMAT insub;
|
|
SUB_Q_CHANNEL_DATA sub;
|
|
long size;
|
|
int pos=0;
|
|
if (!cdrom_drive) return 0;
|
|
|
|
insub.Format = IOCTL_CDROM_CURRENT_POSITION;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
|
|
if (ioctl_cd_state == CD_PLAYING || ioctl_cd_state == CD_PAUSED)
|
|
{
|
|
uint32_t cdpos = ioctl_cd_pos;
|
|
int track = get_track_nr(cdpos);
|
|
uint32_t track_address = toc.TrackData[track].Address[3] +
|
|
(toc.TrackData[track].Address[2] * 75) +
|
|
(toc.TrackData[track].Address[1] * 75 * 60);
|
|
|
|
b[pos++] = sub.CurrentPosition.Control;
|
|
b[pos++] = track + 1;
|
|
b[pos++] = sub.CurrentPosition.IndexNumber;
|
|
|
|
if (msf)
|
|
{
|
|
uint32_t dat = cdpos;
|
|
b[pos + 3] = (uint8_t)(dat % 75); dat /= 75;
|
|
b[pos + 2] = (uint8_t)(dat % 60); dat /= 60;
|
|
b[pos + 1] = (uint8_t)dat;
|
|
b[pos] = 0;
|
|
pos += 4;
|
|
dat = cdpos - track_address;
|
|
b[pos + 3] = (uint8_t)(dat % 75); dat /= 75;
|
|
b[pos + 2] = (uint8_t)(dat % 60); dat /= 60;
|
|
b[pos + 1] = (uint8_t)dat;
|
|
b[pos] = 0;
|
|
pos += 4;
|
|
}
|
|
else
|
|
{
|
|
b[pos++] = (cdpos >> 24) & 0xff;
|
|
b[pos++] = (cdpos >> 16) & 0xff;
|
|
b[pos++] = (cdpos >> 8) & 0xff;
|
|
b[pos++] = cdpos & 0xff;
|
|
cdpos -= track_address;
|
|
b[pos++] = (cdpos >> 24) & 0xff;
|
|
b[pos++] = (cdpos >> 16) & 0xff;
|
|
b[pos++] = (cdpos >> 8) & 0xff;
|
|
b[pos++] = cdpos & 0xff;
|
|
}
|
|
|
|
if (ioctl_cd_state == CD_PLAYING) return 0x11;
|
|
return 0x12;
|
|
}
|
|
|
|
b[pos++]=sub.CurrentPosition.Control;
|
|
b[pos++]=sub.CurrentPosition.TrackNumber;
|
|
b[pos++]=sub.CurrentPosition.IndexNumber;
|
|
|
|
if (msf)
|
|
{
|
|
int c;
|
|
for (c = 0; c < 4; c++)
|
|
b[pos++] = sub.CurrentPosition.AbsoluteAddress[c];
|
|
for (c = 0; c < 4; c++)
|
|
b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c];
|
|
}
|
|
else
|
|
{
|
|
uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]);
|
|
b[pos++] = temp >> 24;
|
|
b[pos++] = temp >> 16;
|
|
b[pos++] = temp >> 8;
|
|
b[pos++] = temp;
|
|
temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]);
|
|
b[pos++] = temp >> 24;
|
|
b[pos++] = temp >> 16;
|
|
b[pos++] = temp >> 8;
|
|
b[pos++] = temp;
|
|
}
|
|
|
|
return 0x13;
|
|
}
|
|
|
|
static void ioctl_eject(void)
|
|
{
|
|
long size;
|
|
if (!cdrom_drive) return;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
}
|
|
|
|
static void ioctl_load(void)
|
|
{
|
|
long size;
|
|
if (!cdrom_drive) return;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0);
|
|
}
|
|
|
|
#define IOCTL_DATA_BUFFER 8192
|
|
|
|
typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
|
|
SCSI_PASS_THROUGH_DIRECT spt;
|
|
ULONG Filler;
|
|
UCHAR SenseBuf[32];
|
|
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
|
|
|
|
static int ioctl_readsector(uint8_t *b, int sector, int count)
|
|
{
|
|
LARGE_INTEGER pos;
|
|
BOOL status;
|
|
long size = 0;
|
|
|
|
if (!cdrom_drive)
|
|
return -1;
|
|
|
|
if (ioctl_cd_state == CD_PLAYING)
|
|
return -1;
|
|
|
|
ioctl_cd_state = CD_STOPPED;
|
|
pos.QuadPart=sector*2048;
|
|
ioctl_open(0);
|
|
SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN);
|
|
status = ReadFile(hIOCTL, b, count*2048, (LPDWORD)&size, NULL);
|
|
ioctl_close();
|
|
|
|
/*If the read 'succeeded' but didn't read all required data, try again using SPTI*/
|
|
if (status && size != count*2048)
|
|
{
|
|
uint8_t cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
|
|
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
|
|
DWORD returned;
|
|
uint8_t *data_buffer;//[IOCTL_DATA_BUFFER];
|
|
|
|
data_buffer = malloc(count * IOCTL_DATA_BUFFER);
|
|
|
|
ioctl_open(0);
|
|
|
|
cmd[9] |= 1 << 4; // userdata
|
|
|
|
cmd[3] = (uint8_t)(sector >> 16);
|
|
cmd[4] = (uint8_t)(sector >> 8);
|
|
cmd[5] = (uint8_t)(sector >> 0);
|
|
cmd[6] = (uint8_t)(count >> 16);
|
|
cmd[7] = (uint8_t)(count >> 8);
|
|
cmd[8] = (uint8_t)(count >> 0);
|
|
|
|
memset(&swb, 0, sizeof (swb));
|
|
memcpy(swb.spt.Cdb, cmd, 12);
|
|
|
|
swb.spt.Length = sizeof (SCSI_PASS_THROUGH);
|
|
swb.spt.CdbLength = 12;
|
|
swb.spt.DataIn = SCSI_IOCTL_DATA_IN;
|
|
swb.spt.DataTransferLength = count*IOCTL_DATA_BUFFER;
|
|
swb.spt.DataBuffer = data_buffer;
|
|
memset(data_buffer, 0, count*IOCTL_DATA_BUFFER);
|
|
swb.spt.TimeOutValue = 80 * 60;
|
|
swb.spt.SenseInfoOffset = (uintptr_t)&swb.SenseBuf - (uintptr_t)&swb;//offsetof(swb, SenseBuf);
|
|
swb.spt.SenseInfoLength = 32;
|
|
|
|
if (DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT,
|
|
&swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
|
|
&swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
|
|
&returned, NULL))
|
|
{
|
|
memcpy(b, data_buffer, count*2048);
|
|
status = 1;
|
|
}
|
|
else
|
|
status = 0;
|
|
|
|
ioctl_close();
|
|
|
|
free(data_buffer);
|
|
}
|
|
|
|
return !status;
|
|
}
|
|
|
|
static int is_track_audio(uint32_t pos)
|
|
{
|
|
int c;
|
|
int control = 0;
|
|
|
|
if (!tocvalid)
|
|
return 0;
|
|
|
|
for (c = 0; toc.TrackData[c].TrackNumber != 0xaa; c++)
|
|
{
|
|
uint32_t track_address = toc.TrackData[c].Address[3] +
|
|
(toc.TrackData[c].Address[2] * 75) +
|
|
(toc.TrackData[c].Address[1] * 75 * 60);
|
|
|
|
if (toc.TrackData[c].TrackNumber >= toc.FirstTrack &&
|
|
toc.TrackData[c].TrackNumber <= toc.LastTrack &&
|
|
track_address >= pos)
|
|
{
|
|
control = toc.TrackData[c].Control;
|
|
break;
|
|
}
|
|
}
|
|
return (control & 4) ? 0 : 1;
|
|
}
|
|
|
|
static int ioctl_is_track_audio(uint32_t pos, int ismsf)
|
|
{
|
|
if (ismsf)
|
|
{
|
|
int m = (pos >> 16) & 0xff;
|
|
int s = (pos >> 8) & 0xff;
|
|
int f = pos & 0xff;
|
|
pos = MSFtoLBA(m, s, f);
|
|
}
|
|
return is_track_audio(pos);
|
|
}
|
|
|
|
static void ioctl_readsector_raw(uint8_t *b, int sector)
|
|
{
|
|
long size;
|
|
|
|
if (!cdrom_drive) return;
|
|
if (ioctl_cd_state == CD_PLAYING)
|
|
return;
|
|
|
|
ioctl_cd_state = CD_STOPPED;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, NULL, 0, b, 1, (LPDWORD)&size, NULL);
|
|
ioctl_close();
|
|
}
|
|
|
|
static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single)
|
|
{
|
|
int len=4;
|
|
long size;
|
|
int c,d;
|
|
uint32_t temp;
|
|
if (!cdrom_drive) return 0;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),(LPDWORD)&size,NULL);
|
|
ioctl_close();
|
|
tocvalid=1;
|
|
// pclog("Read TOC done! %i\n",single);
|
|
b[2]=toc.FirstTrack;
|
|
b[3]=toc.LastTrack;
|
|
d=0;
|
|
for (c=0;c<=toc.LastTrack;c++)
|
|
{
|
|
if (toc.TrackData[c].TrackNumber>=starttrack)
|
|
{
|
|
d=c;
|
|
break;
|
|
}
|
|
}
|
|
last_block = 0;
|
|
for (c=d;c<=toc.LastTrack;c++)
|
|
{
|
|
uint32_t address;
|
|
if ((len+8)>maxlen) break;
|
|
// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));
|
|
b[len++]=0; /*Reserved*/
|
|
b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control;
|
|
b[len++]=toc.TrackData[c].TrackNumber;
|
|
b[len++]=0; /*Reserved*/
|
|
address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
|
|
if (address > last_block)
|
|
last_block = address;
|
|
|
|
if (msf)
|
|
{
|
|
b[len++]=toc.TrackData[c].Address[0];
|
|
b[len++]=toc.TrackData[c].Address[1];
|
|
b[len++]=toc.TrackData[c].Address[2];
|
|
b[len++]=toc.TrackData[c].Address[3];
|
|
}
|
|
else
|
|
{
|
|
temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
|
|
b[len++]=temp>>24;
|
|
b[len++]=temp>>16;
|
|
b[len++]=temp>>8;
|
|
b[len++]=temp;
|
|
}
|
|
if (single) break;
|
|
}
|
|
b[0] = (uint8_t)(((len-2) >> 8) & 0xff);
|
|
b[1] = (uint8_t)((len-2) & 0xff);
|
|
/* pclog("Table of Contents (%i bytes) : \n",size);
|
|
pclog("First track - %02X\n",toc.FirstTrack);
|
|
pclog("Last track - %02X\n",toc.LastTrack);
|
|
for (c=0;c<=toc.LastTrack;c++)
|
|
pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
|
|
for (c=0;c<=toc.LastTrack;c++)
|
|
pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/
|
|
return len;
|
|
}
|
|
|
|
static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen)
|
|
{
|
|
int len=4;
|
|
int size;
|
|
uint32_t temp;
|
|
CDROM_READ_TOC_EX toc_ex;
|
|
CDROM_TOC_SESSION_DATA toc;
|
|
if (!cdrom_drive) return 0;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
memset(&toc_ex,0,sizeof(toc_ex));
|
|
memset(&toc,0,sizeof(toc));
|
|
toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION;
|
|
toc_ex.Msf=msf;
|
|
toc_ex.SessionTrack=0;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL);
|
|
ioctl_close();
|
|
// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber);
|
|
b[2]=toc.FirstCompleteSession;
|
|
b[3]=toc.LastCompleteSession;
|
|
b[len++]=0; /*Reserved*/
|
|
b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control;
|
|
b[len++]=toc.TrackData[0].TrackNumber;
|
|
b[len++]=0; /*Reserved*/
|
|
if (msf)
|
|
{
|
|
b[len++]=toc.TrackData[0].Address[0];
|
|
b[len++]=toc.TrackData[0].Address[1];
|
|
b[len++]=toc.TrackData[0].Address[2];
|
|
b[len++]=toc.TrackData[0].Address[3];
|
|
}
|
|
else
|
|
{
|
|
temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]);
|
|
b[len++]=temp>>24;
|
|
b[len++]=temp>>16;
|
|
b[len++]=temp>>8;
|
|
b[len++]=temp;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static int ioctl_readtoc_raw(unsigned char *b, int maxlen)
|
|
{
|
|
int len=4;
|
|
int size;
|
|
int i;
|
|
CDROM_READ_TOC_EX toc_ex;
|
|
CDROM_TOC_FULL_TOC_DATA toc;
|
|
if (!cdrom_drive) return 0;
|
|
ioctl_cd_state = CD_STOPPED;
|
|
memset(&toc_ex,0,sizeof(toc_ex));
|
|
memset(&toc,0,sizeof(toc));
|
|
toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_FULL_TOC;
|
|
toc_ex.Msf=1;
|
|
toc_ex.SessionTrack=0;
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL);
|
|
ioctl_close();
|
|
// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber);
|
|
b[2]=toc.FirstCompleteSession;
|
|
b[3]=toc.LastCompleteSession;
|
|
|
|
size -= sizeof(CDROM_TOC_FULL_TOC_DATA);
|
|
size /= sizeof(toc.Descriptors[0]);
|
|
|
|
for (i = 0; i <= size; i++)
|
|
{
|
|
b[len++]=toc.Descriptors[i].SessionNumber;
|
|
b[len++]=(toc.Descriptors[i].Adr<<4)|toc.Descriptors[i].Control;
|
|
b[len++]=0;
|
|
b[len++]=toc.Descriptors[i].Reserved1; /*Reserved*/
|
|
b[len++]=toc.Descriptors[i].MsfExtra[0];
|
|
b[len++]=toc.Descriptors[i].MsfExtra[1];
|
|
b[len++]=toc.Descriptors[i].MsfExtra[2];
|
|
b[len++]=toc.Descriptors[i].Zero;
|
|
b[len++]=toc.Descriptors[i].Msf[0];
|
|
b[len++]=toc.Descriptors[i].Msf[1];
|
|
b[len++]=toc.Descriptors[i].Msf[2];
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static uint32_t ioctl_size()
|
|
{
|
|
return cdrom_capacity;
|
|
}
|
|
|
|
static int ioctl_status()
|
|
{
|
|
if (!(ioctl_ready()) && (cdrom_drive <= 0))
|
|
return CD_STATUS_EMPTY;
|
|
|
|
switch(ioctl_cd_state)
|
|
{
|
|
case CD_PLAYING:
|
|
return CD_STATUS_PLAYING;
|
|
case CD_PAUSED:
|
|
return CD_STATUS_PAUSED;
|
|
case CD_STOPPED:
|
|
return CD_STATUS_STOPPED;
|
|
}
|
|
return CD_STATUS_STOPPED;
|
|
}
|
|
|
|
void ioctl_reset()
|
|
{
|
|
CDROM_TOC ltoc;
|
|
long size;
|
|
|
|
if (!cdrom_drive)
|
|
{
|
|
tocvalid = 0;
|
|
return;
|
|
}
|
|
|
|
ioctl_open(0);
|
|
DeviceIoControl(hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), (LPDWORD)&size, NULL);
|
|
ioctl_close();
|
|
|
|
toc = ltoc;
|
|
tocvalid = 1;
|
|
}
|
|
|
|
void ioctl_set_drive(char d)
|
|
{
|
|
ioctl_close();
|
|
|
|
sprintf(ioctl_path, "\\\\.\\%c:", d);
|
|
pclog("Path is %s\n", ioctl_path);
|
|
tocvalid = 0;
|
|
atapi = &ioctl_atapi;
|
|
|
|
ioctl_open(d);
|
|
}
|
|
|
|
int ioctl_open(char d)
|
|
{
|
|
if (hIOCTL)
|
|
ioctl_close();
|
|
hIOCTL = CreateFile(ioctl_path,GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
|
|
if (!hIOCTL)
|
|
{
|
|
//fatal("IOCTL");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void ioctl_close(void)
|
|
{
|
|
if (hIOCTL)
|
|
{
|
|
CloseHandle(hIOCTL);
|
|
hIOCTL = NULL;
|
|
}
|
|
}
|
|
|
|
static void ioctl_exit(void)
|
|
{
|
|
ioctl_stop();
|
|
tocvalid=0;
|
|
}
|
|
|
|
static ATAPI ioctl_atapi=
|
|
{
|
|
ioctl_ready,
|
|
ioctl_medium_changed,
|
|
ioctl_readtoc,
|
|
ioctl_readtoc_session,
|
|
ioctl_readtoc_raw,
|
|
ioctl_getcurrentsubchannel,
|
|
ioctl_readsector,
|
|
ioctl_readsector_raw,
|
|
ioctl_playaudio,
|
|
ioctl_seek,
|
|
ioctl_load,
|
|
ioctl_eject,
|
|
ioctl_pause,
|
|
ioctl_resume,
|
|
ioctl_size,
|
|
ioctl_status,
|
|
ioctl_is_track_audio,
|
|
ioctl_stop,
|
|
ioctl_exit
|
|
};
|