diff --git a/src/cdrom-ioctl-osx.c b/src/cdrom-ioctl-osx.c index 37c800f..4d81bce 100644 --- a/src/cdrom-ioctl-osx.c +++ b/src/cdrom-ioctl-osx.c @@ -4,78 +4,413 @@ #include "ibm.h" #include "ide.h" #include "cdrom-ioctl.h" - +#include +#include +#include +#include +#include +#include +#include +#include +#include static ATAPI ioctl_atapi; int old_cdrom_drive; +static uint32_t cdrom_capacity = 0; +static int tocvalid = 0; +static int toc_tracks; +static int first_track, last_track; +static CDTOC *toc = NULL; +static CDDiscInfo disc_info; +static int track_addr[256]; + +static int msf_to_lba(CDMSF *msf) +{ + return msf->frame + (msf->second * 75) + (msf->minute * 60 * 75); +} + +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; +static int cd_drive = -1; + +static int cd_open() +{ + char s[80]; + + if (cd_drive < 0) + return 0; + + sprintf(s, "disk%i", cd_drive); + return opendev(s, O_RDONLY, 0, NULL); +} +static void cd_close(int fd) +{ + close(fd); +} + void ioctl_audio_callback(int16_t *output, int len) { - memset(output, 0, len * 2); + int ioctl_fd; + +// 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) + { + memset(output, 0, len * 2); + return; + } + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + { + memset(output, 0, len * 2); + return; + } + + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + dk_cd_read_t cd_read; + + bzero(&cd_read, sizeof(cd_read)); + + cd_read.offset = (ioctl_cd_pos-150)*kCDSectorSizeCDDA; + cd_read.buffer = &cd_buffer[cd_buflen]; + cd_read.bufferLength = kCDSectorSizeCDDA; + cd_read.sectorType = kCDSectorTypeCDDA; + cd_read.sectorArea = kCDSectorAreaUser; + //pclog("CDDA read %llx %d %d\n", cd_read.offset, cd_read.bufferLength, ioctl_cd_pos); + + if (ioctl(ioctl_fd, DKIOCCDREAD, &cd_read) < 0) + { + //pclog("DeviceIoControl returned false %d\n", errno); + 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); + } + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + + cd_close(ioctl_fd); + + 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) { - return 0; + int c; + int track = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc->descriptors[c].p.frame + + (toc->descriptors[c].p.second * 75) + + (toc->descriptors[c].p.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + track = c; + } + return track; } static int is_track_audio(uint32_t pos) { - return 0; + int c; + int control = 0; + //pclog("is_track_audio: %08x %i\n", pos, tocvalid); + if (!tocvalid) + return 0; + //pclog(" scan tracks %i-%i\n", first_track, last_track); + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc->descriptors[c].p.frame + + (toc->descriptors[c].p.second * 75) + + (toc->descriptors[c].p.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + control = toc->descriptors[c].control; + } + return (control & 4) ? 0 : 1; } static int ioctl_is_track_audio(uint32_t pos, int ismsf) { - return 0; + if (ismsf) + { + CDMSF msf; + msf.minute = (pos >> 16) & 0xff; + msf.second = (pos >> 8) & 0xff; + msf.frame = pos & 0xff; + pos = msf_to_lba(&msf); + } + return is_track_audio(pos); } static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) { + //pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60); + len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60); + //pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = pos+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, 0, len); } static void ioctl_pause(void) { + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; } static void ioctl_resume(void) { + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; } static void ioctl_stop(void) { + ioctl_cd_state = CD_STOPPED; } static void ioctl_seek(uint32_t pos) { +// pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; } -static int read_toc(int fd, struct cdrom_tocentry *btoc) +static int read_toc(int fd) { - return 0; + dk_cd_read_toc_t cd_read_toc; + dk_cd_read_disc_info_t cd_read_disc_info; + int result; + int c; + + bzero(&cd_read_toc, sizeof(cd_read_toc)); + bzero(&cd_read_disc_info, sizeof(cd_read_disc_info)); + bzero(toc, sizeof(CDTOC) + sizeof(CDTOCDescriptor)*100); + + cd_read_toc.format = kCDTOCFormatTOC; + cd_read_toc.buffer = toc; + cd_read_toc.bufferLength = 2048;//sizeof(CDTOC) + sizeof(CDTOCDescriptor)*100; + //pclog("buffer=%p bufferLength=%u\n", cd_read_toc.buffer, cd_read_toc.bufferLength); + result = ioctl(fd, DKIOCCDREADTOC, &cd_read_toc); + + //pclog("Read_toc - fd=%d result=%d errno=%d toc=%p\n", fd, result, errno, toc); + if (result < 0) + { + //pclog("read_toc: DKIOCCDREADTOC failed\n"); + return 0; + } + + //pclog("toc length=%u first=%u last=%u\n", toc->length, toc->sessionFirst, toc->sessionFirst); + first_track = 1; + last_track = 0; + toc_tracks = CDTOCGetDescriptorCount(toc); + + for (c = 0; c < toc_tracks; c++) + { + if (toc->descriptors[c].session > 1) + continue; + track_addr[c] = msf_to_lba(&toc->descriptors[c].p); + //pclog("Track %i %02x addr %08x\n", c, toc->descriptors[c].point, track_addr[c]); + if (toc->descriptors[c].point <= 99 && toc->descriptors[c].adr == 1) + last_track++; + } + + //pclog("Tracks %i %i %i\n", first_track, last_track, toc_tracks); + + cd_read_disc_info.buffer = &disc_info; + cd_read_disc_info.bufferLength = sizeof(disc_info); + result = ioctl(fd, DKIOCCDREADDISCINFO, &cd_read_disc_info); + if (result < 0) + { + //pclog("read_toc: DKIOCCDREADDISCINFO failed\n"); + return 0; + } + + return 1; } static int ioctl_ready(void) { - return 0; + int ioctl_fd = cd_open(); + //pclog("ioctl_ready - %d %d\n", ioctl_fd, tocvalid); + if (ioctl_fd <= 0) + return 0; + cd_close(ioctl_fd); + + if (tocvalid) + return 1; + + return 0; } static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) { - return 0; + int c; + int lb = 0; + int tv = 0; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return 0; + + //ioctl_cd_state = CD_STOPPED; + + if (!tocvalid) + tv = read_toc(ioctl_fd); + + cd_close(ioctl_fd); + + if (!tv) + return 0; + + for (c = 0; c <= toc_tracks; c++) + { + if (track_addr[c] > lb) + lb = track_addr[c]; + } + return lb; } static int ioctl_medium_changed(void) { - return 0; + dk_cd_read_disc_info_t cd_read_disc_info; + CDDiscInfo new_disc_info; + int result; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return 1; + + bzero(&cd_read_disc_info, sizeof(cd_read_disc_info)); + cd_read_disc_info.buffer = &new_disc_info; + cd_read_disc_info.bufferLength = sizeof(new_disc_info); + result = ioctl(ioctl_fd, DKIOCCDREADDISCINFO, &cd_read_disc_info); + if (result < 0) + { + //pclog("medium_changed: DKIOCCDREADDISCINFO failed\n"); + ioctl_cd_state = CD_STOPPED; + tocvalid = 0; + cd_close(ioctl_fd); + return 1; + } + + if (memcmp(&disc_info, &new_disc_info, sizeof(CDDiscInfo))) + { + //pclog("medium_changed: disc changed\n"); + ioctl_cd_state = CD_STOPPED; + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); + return 1; + } + + cd_close(ioctl_fd); + return 0; } static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) { - return 0x13; + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = track_addr[track]; + long size; + int pos=0; + int err; + uint8_t ret; + + + if (ioctl_cd_state == CD_PLAYING) + ret = 0x11; + else if (ioctl_cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + + b[pos++] = (toc->descriptors[track].adr << 4) | toc->descriptors[track].control; + b[pos++] = toc->descriptors[track].point; + b[pos++] = 0; + + 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; + } + + //pclog("ioctl_getsubchannel: cdpos=%x track_address=%x track=%i state=%i ret=%02x\n", cdpos, track_address, track, ioctl_cd_state, ret); + + return ret; } static void ioctl_eject(void) @@ -88,59 +423,331 @@ static void ioctl_load(void) static int ioctl_readsector(uint8_t *b, int sector, int count) { - return 0; -} + dk_cd_read_t cd_read; + int res; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return -1; + //pclog("Read sector %x %i\n", sector, count); + + bzero(&cd_read, sizeof(cd_read)); + + cd_read.offset = sector*2048; + cd_read.buffer = b; + cd_read.bufferLength = count*2048; + cd_read.sectorType = kCDSectorTypeMode1; + cd_read.sectorArea = kCDSectorAreaUser; + + res = ioctl(ioctl_fd, DKIOCCDREAD, &cd_read); + //pclog("read res = %i %i %i\n", res, cd_read.bufferLength, errno); -static int lba_to_msf(int lba) -{ - return 0; + cd_close(ioctl_fd); + + return 0; } static void ioctl_readsector_raw(uint8_t *b, int sector) { + dk_cd_read_t cd_read; + int res; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return; + //pclog("Read sector %x %i\n", sector, count); + + bzero(&cd_read, sizeof(cd_read)); + + cd_read.offset = sector*kCDSectorSizeWhole; + cd_read.buffer = b; + cd_read.bufferLength = kCDSectorSizeWhole; + cd_read.sectorType = kCDSectorTypeUnknown; + cd_read.sectorArea = kCDSectorAreaUser; + + res = ioctl(ioctl_fd, DKIOCCDREAD, &cd_read); + //pclog("read res = %i %i %i\n", res, cd_read.bufferLength, errno); + + cd_close(ioctl_fd); } static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) { - return 0; + int len=4; + int c,d; + uint32_t temp; + uint32_t last_address = 0; + int seenAA = 0; + + pclog("ioctl_readtoc\n"); + //ioctl_cd_state = CD_STOPPED; + + if (!tocvalid) + { + int ioctl_fd = cd_open(); + + if (ioctl_fd <= 0) + return 4; + + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); + } + if (!tocvalid) + return 4; + + //pclog("Read TOC done! %i\n",single); + b[2] = first_track; + b[3] = last_track; + d = 0; + //pclog("Read TOC starttrack=%i\n", starttrack); + for (c = 0; c <= toc_tracks; c++) + { + if (toc->descriptors[c].point && toc->descriptors[c].point >= starttrack && toc->descriptors[c].point <= 99) + { + d = c; + break; + } + } + //pclog("Start from track %i\n",d); + b[2] = toc->descriptors[c].point; + //last_block = 0; + + for (c = d; c <= toc_tracks; c++) + { + uint32_t address; + if ((len + 8) > maxlen) + break; + //pclog("Len %i max %i Track %02X - %02X %02X %02i:%02i:%02i %08X\n",len,maxlen,toc->descriptors[c].point,toc->descriptors[c].adr,toc->descriptors[c].control,toc->descriptors[c].p.minute, toc->descriptors[c].p.second, toc->descriptors[c].p.frame,track_addr[c]); + address = track_addr[c]; + if (address < last_address) + continue; + if (toc->descriptors[c].point == 0xaa) + seenAA = 1; + last_address = address; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc->descriptors[c].adr << 4) | toc->descriptors[c].control; + b[len++] = toc->descriptors[c].point; + b[len++] = 0; /*Reserved*/ + //if (address > last_block) + // last_block = address; + + if (msf) + { + b[len++] = 0; + b[len++] = toc->descriptors[c].p.minute; + b[len++] = toc->descriptors[c].p.second; + b[len++] = toc->descriptors[c].p.frame; + } + else + { + temp = track_addr[c]; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + + if (!seenAA && !single) + { + uint32_t lb = 0; + + for (c = 0; c <= toc_tracks; c++) + { + if (track_addr[c] > lb) + lb = track_addr[c]; + } + //pclog("Track AA - %08x %i\n", lb, len); + b[len++] = 0; /*Reserved*/ + b[len++] = (1 << 4) | 1; + b[len++] = 0xaa; + b[len++] = 0; /*Reserved*/ + + if (msf) + { + b[len++] = 0; + b[len++] = (lb / 60) / 75; + b[len++] = (lb / 75) % 60; + b[len++] = lb % 75; + } + else + { + temp = track_addr[c]; + b[len++] = lb >> 24; + b[len++] = lb >> 16; + b[len++] = lb >> 8; + b[len++] = lb; + } + } + + 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", first_track); + pclog("Last track - %02X\n", last_track); + for (c = 0; c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, 0, toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + for (c = 0;c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame));*/ + return len; } static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) { - return 0; + int len = 4; + int session = 0, first_track_nr = 0; + int c, d; + + if (!tocvalid) + { + int ioctl_fd = cd_open(); + + if (ioctl_fd <= 0) + return 4; + + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); + } + + if (!tocvalid) + return 4; + + for (c = 0; c <= toc_tracks; c++) + { + if (toc->descriptors[c].point && toc->descriptors[c].point <= 99) + { + if (toc->descriptors[c].session > session || (toc->descriptors[c].session == session && toc->descriptors[c].point < first_track_nr)) + { + session = toc->descriptors[c].session; + first_track_nr = toc->descriptors[c].point; + d = c; + } + } + } + + b[2] = toc->sessionFirst; + b[3] = toc->sessionLast; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc->descriptors[d].adr << 4) | toc->descriptors[d].control; + b[len++] = toc->descriptors[d].point; + b[len++] = 0; /*Reserved*/ + if (msf) + { + b[len++] = 0; + b[len++] = toc->descriptors[d].p.minute; + b[len++] = toc->descriptors[d].p.second; + b[len++] = toc->descriptors[d].p.frame; + } + else + { + uint32_t temp = track_addr[d]; + 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) { - return 0; + int len = 4; + int ioctl_fd; + int track; + +//pclog("read_toc\n"); + if (!tocvalid) + return 0; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return 0; + cd_close(ioctl_fd); + + b[2] = toc->sessionFirst; + b[3] = toc->sessionLast; + + for (track = 0; track <= toc_tracks; track++) + { + if ((len + 11) > maxlen) + { + pclog("ioctl_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + return len; + } + + +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + + b[len++] = toc->descriptors[track].session; + b[len++] = (toc->descriptors[track].adr << 4) | toc->descriptors[track].control; + b[len++] = toc->descriptors[track].tno; + b[len++] = toc->descriptors[track].point; + b[len++] = toc->descriptors[track].address.minute; + b[len++] = toc->descriptors[track].address.second; + b[len++] = toc->descriptors[track].address.frame; + b[len++] = toc->descriptors[track].zero; + b[len++] = toc->descriptors[track].p.minute; + b[len++] = toc->descriptors[track].p.second; + b[len++] = toc->descriptors[track].p.frame; + } + + return len; } static uint32_t ioctl_size() { - return 0; + return cdrom_capacity; } static int ioctl_status() { - return CD_STATUS_EMPTY; + if (!ioctl_ready) + return CD_STATUS_EMPTY; + return CD_STATUS_STOPPED; } void ioctl_reset() { + int ioctl_fd; + + tocvalid = 0; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return; + + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); } void ioctl_set_drive(char d) { - atapi = &ioctl_atapi; + ioctl_close(); + atapi=&ioctl_atapi; + ioctl_open(d); } int ioctl_open(char d) { atapi = &ioctl_atapi; + + toc = malloc(2048); + + cd_drive = d; return 0; } void ioctl_close(void) { + if (toc) + { + free(toc); + toc = NULL; + } } static void ioctl_exit(void) diff --git a/src/wx-sdl2.c b/src/wx-sdl2.c index 940d931..50e7a44 100644 --- a/src/wx-sdl2.c +++ b/src/wx-sdl2.c @@ -42,6 +42,14 @@ #include "wx-common.h" #include "wx-display.h" +#if __APPLE__ +#define pause __pause +#include +#include +#include +#undef pause +#endif + extern void creatediscimage_open(void *hwnd); #define ID_IS(s) wParam == wx_xrcid(s) @@ -383,8 +391,27 @@ void wx_initmenu() } #elif __linux__ wx_appendmenu(cdrom_submenu, IDM_CDROM_REAL+1, "Host CD/DVD Drive (/dev/cdrom)", wxITEM_RADIO); +#elif __APPLE__ + int c; + + for (c = 1; c < 99; c++) + { + char s[80]; + int fd; + + sprintf(s, "disk%i", c); + fd = opendev(s, O_RDONLY, 0, NULL); + if (fd > 0) + { + char name[255]; + + close(fd); + + sprintf(name, "Host CD/DVD Drive (/dev/disk%i)", c); + wx_appendmenu(cdrom_submenu, IDM_CDROM_REAL+c, name, wxITEM_RADIO); + } + } #endif - } int wx_setupmenu(void* data)