]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
2210b3
authorToni Wilen <twilen@winuae.net>
Fri, 16 Jul 2010 12:30:20 +0000 (15:30 +0300)
committerToni Wilen <twilen@winuae.net>
Fri, 16 Jul 2010 12:30:20 +0000 (15:30 +0300)
43 files changed:
a2091.cpp
akiko.cpp
audio.cpp
blkdev.cpp
blkdev_cdimage.cpp
cdtv.cpp
cfgfile.cpp
custom.cpp
debug.cpp
disk.cpp
drawing.cpp
include/blkdev.h
include/cdtv.h
include/custom.h
include/debug.h
include/keyboard.h
include/options.h
include/savestate.h
include/scsidev.h
inputdevice.cpp
inputevents.def
keybuf.cpp
od-win32/blkdev_win32_aspi.cpp
od-win32/blkdev_win32_ioctl.cpp
od-win32/blkdev_win32_spti.cpp
od-win32/dinput.cpp
od-win32/fsdb_mywin32.cpp
od-win32/keyboard_win32.cpp
od-win32/parser.cpp
od-win32/parser.h
od-win32/resources/resource
od-win32/resources/winuae.rc
od-win32/rp.cpp
od-win32/win32.cpp
od-win32/win32.h
od-win32/win32gui.cpp
od-win32/winuae_msvc10/winuae_msvc.vcxproj
od-win32/winuae_msvc10/winuae_msvc.vcxproj.filters
od-win32/winuaechangelog.txt
sana2.cpp
savestate.cpp
scsiemul.cpp
zfile.cpp

index 32237438213bb62e599114147ea39561fcfc8c1a..fe1b481648215d2d5481036be10465fbe66a4ace 100644 (file)
--- a/a2091.cpp
+++ b/a2091.cpp
@@ -1235,7 +1235,7 @@ static void addnativescsi (void)
                types[i] = -1;
                devices[i] = -1;
                if (sys_command_open (DF_SCSI, i)) {
-                       if (sys_command_info (DF_SCSI, i, &dis[i])) {
+                       if (sys_command_info (DF_SCSI, i, &dis[i], 0)) {
                                devices[i] = i;
                                types[i] = 100 - i;
                                if (dis[i].type == INQ_ROMD)
index c4229fb77b76eeea2349cda6d7334ff827001198..c3a7396defc98c5d0db9fd53be82c606ae2ac0f3 100644 (file)
--- a/akiko.cpp
+++ b/akiko.cpp
@@ -7,7 +7,7 @@
 * - NVRAM
 * - CDROM
 *
-* Copyright 2001-2009 Toni Wilen
+* Copyright 2001-2010 Toni Wilen
 *
 */
 
@@ -355,13 +355,7 @@ static uae_u32 akiko_c2p_read (int offset)
 
 #define CDS_ERROR 0x80
 #define CDS_PLAYING 0x08
-
-#define AUDIO_STATUS_NOT_SUPPORTED  0x00
-#define AUDIO_STATUS_IN_PROGRESS    0x11
-#define AUDIO_STATUS_PAUSED         0x12
-#define AUDIO_STATUS_PLAY_COMPLETE  0x13
-#define AUDIO_STATUS_PLAY_ERROR     0x14
-#define AUDIO_STATUS_NO_STATUS      0x15
+#define CDS_PLAYEND 0x00
 
 #define CH_ERR_BADCOMMAND       0x80 // %10000000
 #define CH_ERR_CHECKSUM         0x88 // %10001000
@@ -377,6 +371,13 @@ static uae_u32 akiko_c2p_read (int offset)
 #define CH_ERR_ABNORMALSEEK     0xf0 // %11110000
 #define CH_ERR_NODISK           0xf8 // %11111000
 
+static int framecounter, subcodecounter;
+
+#define MAX_SUBCODEBUFFER 20
+static volatile int subcodebufferoffset, subcodebufferoffsetw;
+static uae_u8 subcodebufferinuse[MAX_SUBCODEBUFFER];
+static uae_u8 subcodebuffer[MAX_SUBCODEBUFFER * SUB_CHANNEL_SIZE];
+
 static uae_u32 cdrom_intreq, cdrom_intena;
 static uae_u8 cdrom_subcodeoffset;
 static uae_u32 cdrom_addressdata, cdrom_addressmisc;
@@ -391,13 +392,11 @@ static uae_u8 cdrom_result_buffer[32];
 static uae_u8 cdrom_command_buffer[32];
 static uae_u8 cdrom_command;
 
-#define        MAX_TOC_ENTRIES 103 /* tracks 1-99, A0, A1 and A2 */
-static int cdrom_toc_entries;
 static int cdrom_toc_counter;
 static uae_u32 cdrom_toc_crc;
 static uae_u8 cdrom_toc_buffer[MAX_TOC_ENTRIES * 13];
-static uae_u8 cdrom_toc_cd_buffer[4 + MAX_TOC_ENTRIES * 11];
-static uae_u8 qcode_buf[12];
+static struct cd_toc_head cdrom_toc_cd_buffer;
+static uae_u8 qcode_buf[SUBQ_SIZE];
 static int qcode_valid;
 
 static int cdrom_disk, cdrom_paused, cdrom_playing;
@@ -406,7 +405,7 @@ static int cdrom_command_length;
 static int cdrom_checksum_error, cdrom_unknown_command;
 static int cdrom_data_offset, cdrom_speed, cdrom_sector_counter;
 static int cdrom_current_sector, cdrom_seek_delay;
-static int cdrom_data_end, cdrom_leadout;
+static int cdrom_data_end;
 static int cdrom_audiotimeout;
 static int cdrom_led;
 static int cdrom_dosomething;
@@ -428,6 +427,7 @@ static volatile int frame2counter;
 
 static smp_comm_pipe requests;
 static volatile int akiko_thread_running;
+static uae_sem_t akiko_sem, sub_sem;
 
 static void checkint (void)
 {
@@ -447,45 +447,11 @@ void rethink_akiko (void)
        checkint ();
 }
 
-
-static uae_u8 frombcd (uae_u8 v)
-{
-       return (v >> 4) * 10 + (v & 15);
-}
-
-static uae_u8 tobcd (uae_u8 v)
-{
-       return ((v / 10) << 4) | (v % 10);
-}
-
-static int fromlongbcd (uae_u8 *p)
-{
-       return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2])  << 0);
-}
-
-/* convert minutes, seconds and frames -> logical sector number */
-static int msf2lsn (int msf)
-{
-       int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff)) - 150;
-       if (sector < 0)
-               sector = 0;
-       return sector;
-}
-
-/* convert logical sector number -> minutes, seconds and frames */
-static int lsn2msf (int sectors)
-{
-       int msf;
-       sectors += 150;
-       msf = (sectors / (75 * 60)) << 16;
-       msf |= ((sectors / 75) % 60) << 8;
-       msf |= (sectors % 75) << 0;
-       return msf;
-}
-
 static void cdaudiostop_do (void)
 {
        qcode_valid = 0;
+       cdrom_playing = 0;
+       cdrom_paused = 0;
        if (unitnum < 0)
                return;
        sys_command_cd_pause (DF_IOCTL, unitnum, 0);
@@ -497,81 +463,116 @@ static void cdaudiostop (void)
 {
        cdrom_playing = 0;
        cdrom_paused = 0;
-       cdrom_audiotimeout = 0;
        write_comm_pipe_u32 (&requests, 0x104, 1);
 }
 
+static void subfunc (uae_u8 *data, int cnt)
+{
+       if (!(cdrom_flags & CDFLAG_SUBCODE))
+               return;
+       uae_sem_wait (&sub_sem);
+#if 0
+       int total = 0;
+       for (int i = 0; i < MAX_SUBCODEBUFFER; i++) {
+               if (subcodebufferinuse[i])
+                       total++;
+       }
+       write_log (L"%d ", total);
+#endif
+       if (subcodebufferinuse[subcodebufferoffsetw]) {
+               memset (subcodebufferinuse, 0,sizeof (subcodebufferinuse));
+               subcodebufferoffsetw = subcodebufferoffset = 0;
+               uae_sem_post (&sub_sem);
+               write_log (L"CD32: subcode buffer overflow 1\n");
+               return;
+       }
+       int offset = subcodebufferoffsetw;
+       while (cnt > 0) {
+               if (subcodebufferinuse[offset]) {
+                       write_log (L"CD32: subcode buffer overflow 2\n");
+                       break;
+               }
+               subcodebufferinuse[offset] = 1;
+               memcpy (&subcodebuffer[offset * SUB_CHANNEL_SIZE], data, SUB_CHANNEL_SIZE);
+               data += SUB_CHANNEL_SIZE;
+               offset++;
+               if (offset >= MAX_SUBCODEBUFFER)
+                       offset = 0;
+               cnt--;
+       }
+       subcodebufferoffsetw = offset;
+       uae_sem_post (&sub_sem);
+}
+
 static void cdaudioplay_do (void)
 {
-       uae_u32 startmsf = read_comm_pipe_u32_blocking (&requests);
-       uae_u32 endmsf = read_comm_pipe_u32_blocking (&requests);
+       uae_u32 startlsn = read_comm_pipe_u32_blocking (&requests);
+       uae_u32 endlsn = read_comm_pipe_u32_blocking (&requests);
        uae_u32 scan = read_comm_pipe_u32_blocking (&requests);
        qcode_valid = 0;
        if (unitnum < 0)
                return;
-       sys_command_cd_play (DF_IOCTL, unitnum, startmsf, endmsf, scan);
+       sys_command_cd_play (DF_IOCTL, unitnum, startlsn, endlsn, scan, subfunc);
 }
 
-static bool isaudiotrack (uae_u32 startmsf)
+static bool isaudiotrack (int startlsn)
 {
-       uae_u8 *buf = cdrom_toc_cd_buffer;
-       uae_u8 *s = NULL;
+       struct cd_toc *s = NULL;
        uae_u32 addr;
        int i;
 
-       if (!cdrom_toc_entries)
+       if (!cdrom_toc_cd_buffer.points)
                return false;
-       for (i = 0; i < cdrom_toc_entries; i++) {
-               s = buf + 4 + i * 11;
-               addr = (s[8] << 16) | (s[9] << 8) | (s[10] << 0);
-               if (s[3] > 0 && s[3] < 100 && addr >= startmsf)
+       for (i = 0; i < cdrom_toc_cd_buffer.points; i++) {
+               s = &cdrom_toc_cd_buffer.toc[i];
+               addr = s->paddress;
+               if (s->track > 0 && s->track < 100 && addr >= startlsn)
                        break;
+               s++;
        }
-       if (s && (s[1] & 0x0c) == 0x04) {
-               write_log (L"tried to play data track %d!\n", s[3]);
+       if (s && (s->control & 0x0c) == 0x04) {
+               write_log (L"tried to play data track %d!\n", s->track);
                return false;
        }
        return true;
 }
 
 
-static uae_u32 last_play_end;
-static int cd_play_audio (uae_u32 startmsf, uae_u32 endmsf, int scan)
+static int last_play_end;
+static int cd_play_audio (int startlsn, int endlsn, int scan)
 {
-       uae_u8 *buf = cdrom_toc_cd_buffer;
-       uae_u8 *s = NULL;
+       struct cd_toc *s = NULL;
        uae_u32 addr;
        int i;
 
-       if (!cdrom_toc_entries)
+       if (!cdrom_toc_cd_buffer.points)
                return 0;
-       for (i = 0; i < cdrom_toc_entries; i++) {
-               s = buf + 4 + i * 11;
-               addr = (s[8] << 16) | (s[9] << 8) | (s[10] << 0);
-               if (s[3] > 0 && s[3] < 100 && addr >= startmsf)
+       for (i = 0; i < cdrom_toc_cd_buffer.points; i++) {
+               s = &cdrom_toc_cd_buffer.toc[i];
+               addr = s->paddress;
+               if (s->track > 0 && s->track < 100 && addr >= startlsn)
                        break;
        }
-       if (s && (s[1] & 0x0c) == 0x04) {
-               write_log (L"tried to play data track %d!\n", s[3]);
-               s += 11;
-               startmsf = (s[8] << 16) | (s[9] << 8) | (s[10] << 0);
-               s += 11;
-               endmsf = (s[8] << 16) | (s[9] << 8) | (s[10] << 0);
-               //cdrom_audiotimeout = 312;
+       if (s && (s->control & 0x0c) == 0x04) {
+               write_log (L"tried to play data track %d!\n", s->track);
+               s++;
+               startlsn = s->paddress;
+               s++;
+               endlsn = s->paddress;
                return 0;
        }
-       last_play_end = endmsf;
+       last_play_end = endlsn;
        cdrom_audiotimeout = 0;
        write_comm_pipe_u32 (&requests, 0x0110, 0);
-       write_comm_pipe_u32 (&requests, startmsf, 0);
-       write_comm_pipe_u32 (&requests, endmsf, 0);
+       write_comm_pipe_u32 (&requests, startlsn, 0);
+       write_comm_pipe_u32 (&requests, endlsn, 0);
        write_comm_pipe_u32 (&requests, scan, 1);
        return 1;
 }
 
 
 /* read qcode */
-static uae_u32 last_play_pos;
+static int last_play_pos;
 static int cd_qcode (uae_u8 *d)
 {
        uae_u8 *buf, *s, as;
@@ -579,39 +580,36 @@ static int cd_qcode (uae_u8 *d)
        if (d)
                memset (d, 0, 11);
        last_play_pos = 0;
-       if (!qcode_valid)
-               return 0;
        buf = qcode_buf;
        as = buf[1];
-       if (as != 0x11 && as != 0x12 && as != 0x13 && as != 0x15) /* audio status ok? */
+       if (as != AUDIO_STATUS_IN_PROGRESS && as != AUDIO_STATUS_PAUSED && as != AUDIO_STATUS_PLAY_COMPLETE && as != AUDIO_STATUS_NO_STATUS) /* audio status ok? */
                return 0;
        s = buf + 4;
-       last_play_pos = (s[5] << 16) | (s[6] << 8) | (s[7] << 0);
+       last_play_pos = msf2lsn (fromlongbcd (s + 7));
        if (!d)
                return 0;
        /* ??? */
        d[0] = 0;
        /* CtlAdr */
-       d[1] = (s[1] >> 4) | (s[1] << 4);
+       d[1] = s[0];
        /* Track */
-       d[2] = tobcd (s[2]);
+       d[2] = s[1];
        /* Index */
-       d[3] = tobcd (s[3]);
+       d[3] = s[2];
        /* TrackPos */
-       d[4] = tobcd (s[9]);
-       d[5] = tobcd (s[10]);
-       d[6] = tobcd (s[11]);
+       d[4] = s[3];
+       d[5] = s[4];
+       d[6] = s[5];
        /* DiskPos */
        d[7] = 0;
-       d[8] = tobcd (s[5]);
-       d[9] = tobcd (s[6]);
-       d[10] = tobcd (s[7]);
-       if (as == 0x15) {
+       d[8] = s[7];
+       d[9] = s[8];
+       d[10] = s[9];
+       if (as == AUDIO_STATUS_IN_PROGRESS) {
                /* Make sure end of disc position is not missed.
                */
-               int lsn = msf2lsn ((s[5] << 16) | (s[6] << 8) | (s[7] << 0));
-               int msf = lsn2msf (cdrom_leadout);
-               if (lsn >= cdrom_leadout || cdrom_leadout - lsn < 10) {
+               if (last_play_pos >= cdrom_toc_cd_buffer.lastaddress || cdrom_toc_cd_buffer.lastaddress - last_play_pos < 10) {
+                       int msf = lsn2msf (cdrom_toc_cd_buffer.lastaddress);
                        d[8] = tobcd ((uae_u8)(msf >> 16));
                        d[9] = tobcd ((uae_u8)(msf >> 8));
                        d[10] = tobcd ((uae_u8)(msf >> 0));
@@ -621,49 +619,42 @@ static int cd_qcode (uae_u8 *d)
 }
 
 /* read toc */
-static int cdrom_toc (void)
+static int get_cdrom_toc (void)
 {
-       int i, j;
+       int j;
        int datatrack = 0, secondtrack = 0;
-       uae_u8 *s, *d, *buf;
+       struct cd_toc_head *th;
 
        cdrom_toc_counter = -1;
-       cdrom_toc_entries = 0;
-       buf = sys_command_cd_toc (DF_IOCTL, unitnum);
-       if (!buf)
+       th = sys_command_cd_toc (DF_IOCTL, unitnum);
+       if (!th)
                return 1;
-       i = (buf[0] << 8) | (buf[1] << 0);
-       i -= 2;
-       i /= 11;
-       if (i > MAX_TOC_ENTRIES)
-               return -1;
-       cdrom_toc_entries = i;
+       memcpy (&cdrom_toc_cd_buffer, th, sizeof cdrom_toc_cd_buffer);
        memset (cdrom_toc_buffer, 0, MAX_TOC_ENTRIES * 13);
-       memcpy (cdrom_toc_cd_buffer, buf, 4 + cdrom_toc_entries * 11);
        cdrom_data_end = -1;
-       for (j = 0; j < cdrom_toc_entries; j++) {
-               uae_u32 addr;
-               s = buf + 4 + j * 11;
-               d = &cdrom_toc_buffer[j * 13];
-               addr = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0));
-               d[1] = (s[1] >> 4) | (s[1] << 4);
-               d[3] = s[3] < 100 ? tobcd(s[3]) : s[3];
-               d[8] = tobcd (s[8]);
-               d[9] = tobcd (s[9]);
-               d[10] = tobcd (s[10]);
-               if (s[3] == 1 && (s[1] & 0x0c) == 0x04)
+       for (j = 0; j < th->points; j++) {
+               struct cd_toc *s = &th->toc[j];
+               uae_u8 *d = &cdrom_toc_buffer[j * 13];
+               int addr = s->paddress;
+               int msf = lsn2msf (addr);
+               if (s->point == 0xa0 || s->point == 0xa1)
+                       msf = s->track << 16;
+               d[1] = (s->adr << 0) | (s->control << 4);
+               d[3] = s->point < 100 ? tobcd (s->point) : s->point;
+               d[8] = tobcd ((msf >> 16) & 0xff);
+               d[9] = tobcd ((msf >> 8) & 0xff);
+               d[10] = tobcd ((msf >> 0) & 0xff);
+               if (s->point == 1 && (s->control & 0x0c) == 0x04)
                        datatrack = 1;
-               if (s[3] == 2)
+               if (s->point == 2)
                        secondtrack = addr;
-               if (s[3] == 0xa2)
-                       cdrom_leadout = addr;
        }
-       cdrom_toc_crc = get_crc32(cdrom_toc_buffer, cdrom_toc_entries * 13);
+       cdrom_toc_crc = get_crc32 (cdrom_toc_buffer, cdrom_toc_cd_buffer.points * 13);
        if (datatrack) {
                if (secondtrack)
                        cdrom_data_end = secondtrack;
                else
-                       cdrom_data_end = cdrom_leadout;
+                       cdrom_data_end = cdrom_toc_cd_buffer.lastaddress;
        }
        return 0;
 }
@@ -682,21 +673,21 @@ static int sys_cddev_open (void)
                opened[unitnum] = 0;
                if (sys_command_open (DF_IOCTL, unitnum)) {
                        opened[unitnum] = 1;
-                       di2 = sys_command_info (DF_IOCTL, unitnum, &di1);
+                       di2 = sys_command_info (DF_IOCTL, unitnum, &di1, 0);
                        if (di2 && di2->type == INQ_ROMD) {
                                write_log (L"%s: ", di2->label);
                                if (first < 0)
                                        first = unitnum;
-                               if (!cdrom_toc ()) {
+                               if (!get_cdrom_toc ()) {
                                        if (cdrom_data_end > 0) {
-                                               uae_u8 *p = sys_command_cd_read (DF_IOCTL, unitnum, 16);
+                                               uae_u8 *p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, 16, 1);
                                                if (p) {
                                                        if (!memcmp (p + 8, "CDTV", 4) || !memcmp (p + 8, "CD32", 4)) {
                                                                uae_u32 crc;
                                                                write_log (L"CD32 or CDTV");
                                                                if (cd32unit < 0)
                                                                        cd32unit = unitnum;
-                                                               p = sys_command_cd_read (DF_IOCTL, unitnum, 21);
+                                                               p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, 21, 1);
                                                                crc = get_crc32 (p, 2048);
                                                                if (crc == 0xe56c340f)
                                                                        write_log (L" [CD32.TM]");
@@ -731,7 +722,7 @@ static int sys_cddev_open (void)
        }
        if (unitnum < 0)
                return 1;
-       di2 = sys_command_info (DF_IOCTL, unitnum, &di1);
+       di2 = sys_command_info (DF_IOCTL, unitnum, &di1, 0);
        if (!di2) {
                write_log (L"unit %d info failed\n", unitnum);
                sys_command_close (DF_IOCTL, unitnum);
@@ -785,7 +776,7 @@ static void cdrom_return_data (void)
        }
        put_byte (cmd_buf + ((cdcomrxinx + len) & 0xff), checksum);
 #if AKIKO_DEBUG_IO_CMD
-       write_log (L"%02X\n", checksum);
+       write_log (L"(%02X)\n", checksum);
 #endif
        cdcomrxinx += len + 1;
        cdcomrxinx &= 0xff;
@@ -812,7 +803,11 @@ static int cdrom_command_led (void)
 static int cdrom_command_media_status (void)
 {
        cdrom_result_buffer[0] = 0x0a;
-       cdrom_result_buffer[1] = sys_command_ismedia (DF_IOCTL, unitnum, 0) > 0 ? 0x83: 0x80;
+       if (cd_hunt) {
+               cdrom_result_buffer[1] = 0x80;
+       } else {
+               cdrom_result_buffer[1] = sys_command_ismedia (DF_IOCTL, unitnum, 0) > 0 ? 0x83: 0x80;
+       }
        return 2;
 }
 
@@ -822,7 +817,7 @@ static int cdrom_command_status (void)
        cdrom_result_buffer[1] = 0x01;
        //cdrom_result_buffer[1] = 0x80; door open
        if (unitnum >= 0)
-               cdrom_toc ();
+               get_cdrom_toc ();
        /* firmware info */
        memcpy (cdrom_result_buffer + 2, FIRMWAREVERSION, sizeof FIRMWAREVERSION);
        cdrom_result_buffer[0] = cdrom_command;
@@ -834,17 +829,18 @@ static int cdrom_command_status (void)
 static int cdrom_return_toc_entry (void)
 {
        cdrom_result_buffer[0] = 6;
-       if (cdrom_toc_entries == 0) {
+       if (cdrom_toc_cd_buffer.points == 0) {
                cdrom_result_buffer[1] = CDS_ERROR;
                return 15;
        }
        cdrom_result_buffer[1] = 0;
        memcpy (cdrom_result_buffer + 2, cdrom_toc_buffer + cdrom_toc_counter * 13, 13);
        cdrom_toc_counter++;
-       if (cdrom_toc_counter >= cdrom_toc_entries)
+       if (cdrom_toc_counter >= cdrom_toc_cd_buffer.points)
                cdrom_toc_counter = -1;
        return 15;
 }
+
 static int checkerr (void)
 {
        if (!cdrom_disk) {
@@ -854,9 +850,21 @@ static int checkerr (void)
        return 0;
 }
 
+static int cdrom_command_stop (void)
+{
+       cdrom_audiotimeout = 0;
+       cdrom_result_buffer[0] = cdrom_command;
+       if (checkerr ())
+               return 2;
+       cdrom_result_buffer[1] = 0;
+       write_comm_pipe_u32 (&requests, 0x0104, 1);
+       return 2;
+}
+
 /* pause CD audio */
 static int cdrom_command_pause (void)
 {
+       cdrom_audiotimeout = 0;
        cdrom_toc_counter = -1;
        cdrom_result_buffer[0] = cdrom_command;
        if (checkerr ())
@@ -866,8 +874,7 @@ static int cdrom_command_pause (void)
                return 2;
        if (cdrom_paused)
                return 2;
-       cdrom_audiotimeout = 0;
-       write_comm_pipe_u32 (&requests, 0x102, 1);
+       write_comm_pipe_u32 (&requests, 0x0102, 1);
        cdrom_paused = 1;
        return 2;
 }
@@ -884,15 +891,15 @@ static int cdrom_command_unpause (void)
        if (!cdrom_playing)
                return 2;
        cdrom_paused = 0;
-       write_comm_pipe_u32 (&requests, 0x103, 1);
+       write_comm_pipe_u32 (&requests, 0x0103, 1);
        return 2;
 }
 
 /* seek        head/play CD audio/read data sectors */
 static int cdrom_command_multi (void)
 {
-       int seekpos = fromlongbcd (cdrom_command_buffer + 1);
-       int endpos = fromlongbcd (cdrom_command_buffer + 4);
+       int seekpos = msf2lsn (fromlongbcd (cdrom_command_buffer + 1));
+       int endpos = msf2lsn (fromlongbcd (cdrom_command_buffer + 4));
 
        if (cdrom_playing)
                cdaudiostop ();
@@ -904,9 +911,9 @@ static int cdrom_command_multi (void)
                return 2;
        }
 
-       if (cdrom_command_buffer[7] == 0x80) {    /* data read */
-               int cdrom_data_offset_end = msf2lsn (endpos);
-               cdrom_data_offset = msf2lsn (seekpos);
+       if (cdrom_command_buffer[7] == 0x80) { /* data read */
+               int cdrom_data_offset_end = endpos;
+               cdrom_data_offset = seekpos;
                cdrom_seek_delay = abs (cdrom_current_sector - cdrom_data_offset);
                if (cdrom_seek_delay < 100) {
                        cdrom_seek_delay = 1;
@@ -949,13 +956,19 @@ static int cdrom_command_multi (void)
        return 2;
 }
 
+static int cdrom_playend_notify (void)
+{
+       cdrom_result_buffer[0] = 4;
+       cdrom_result_buffer[1] = 0x80;
+       return 2;
+}
+
 /* return subq entry */
 static int cdrom_command_subq (void)
 {
        cdrom_result_buffer[0] = cdrom_command;
        cdrom_result_buffer[1] = 0;
-       if (cd_qcode (cdrom_result_buffer + 2))
-               cdrom_result_buffer[1] = CDS_ERROR;
+       cd_qcode (cdrom_result_buffer + 2);
        return 15;
 }
 
@@ -1027,6 +1040,9 @@ static void cdrom_run_command_run (void)
        memset (cdrom_result_buffer, 0, sizeof (cdrom_result_buffer));
        switch (cdrom_command & 0x0f)
        {
+       case 1:
+               len = cdrom_command_stop ();
+               break;
        case 2:
                len = cdrom_command_pause ();
                break;
@@ -1120,7 +1136,6 @@ static void cdrom_run_read (void)
                cdrom_sector_counter++;
 }
 
-static uae_sem_t akiko_sem;
 static int lastmediastate = 0;
 
 static void akiko_handler (void)
@@ -1129,24 +1144,28 @@ static void akiko_handler (void)
                return;
        if (!cd_initialized || cdrom_receive_started)
                return;
-#if 0
-       if (cdrom_result_complete > cdcomrxcmp && cdrom_result_complete - cdcomrxcmp < 100) {
-               //set_status (CDINTERRUPT_RXDMADONE);
-               return;
-       }
-       if (cdcomrxcmp < cdrom_result_complete)
-               return;
-#endif
+
        if (mediachanged) {
                mediachanged = 0;
                cdrom_start_return_data (cdrom_command_media_status ());
-               if (!lastmediastate)
-                       cd_hunt = 1;
-               cdrom_toc ();
+               get_cdrom_toc ();
                /* do not remove! first try may fail */
-               cdrom_toc ();
+               get_cdrom_toc ();
                return;
        }
+       if (cdrom_audiotimeout == -1) { // play finished (or disk end)
+               if (cdrom_playing) {
+                       write_comm_pipe_u32 (&requests, 0x0104, 1);
+                       cdrom_audiotimeout = -2;
+               } else {
+                       cdrom_audiotimeout = 0;
+               }
+       }
+       if (cdrom_audiotimeout == -2 && qcode_buf[1] != AUDIO_STATUS_IN_PROGRESS) {
+               cdrom_start_return_data (cdrom_playend_notify ());
+               cdrom_audiotimeout = 0;
+       }
+
        if (cdrom_toc_counter >= 0 && !cdrom_command_active && cdrom_dosomething) {
                cdrom_start_return_data (cdrom_return_toc_entry ());
                cdrom_dosomething--;
@@ -1191,23 +1210,22 @@ static void do_hunt (void)
        }
        if (sys_command_open (DF_IOCTL, i) > 0) {
                struct device_info di = { 0 };
-               sys_command_info (DF_IOCTL, i, &di);
+               sys_command_info (DF_IOCTL, i, &di, 0);
                unitnum = i;
                cd_hunt = 0;
+               lastmediastate = -1;
                write_log (L"CD32: autodetected unit %d ('%s')\n", unitnum, di.label);
        }
 }
 
 void AKIKO_hsync_handler (void)
 {
-       static int framecounter;
-
        if (!currprefs.cs_cd32cd || !akiko_inited)
                return;
 
        if (cd_hunt) {
                static int huntcnt;
-               if (huntcnt <= 0) {
+               if (huntcnt <= 0 && !mediachanged) {
                        do_hunt ();
                        huntcnt = 312 * 50 * 2;
                }
@@ -1216,7 +1234,6 @@ void AKIKO_hsync_handler (void)
 
        framecounter--;
        if (framecounter <= 0) {
-               int i;
                if (cdrom_led) {
                        if (cdrom_playing)
                                cdrom_led |= LED_CD_AUDIO;
@@ -1230,17 +1247,31 @@ void AKIKO_hsync_handler (void)
                        cdrom_seek_delay--;
                }
                framecounter = 1000000 / (63 * 75 * cdrom_speed);
-               if (cdrom_flags & CDFLAG_SUBCODE) {
-                       set_status (CDINTERRUPT_SUBCODE);
-                       if (cdrom_subcodeoffset >= 128)
-                               cdrom_subcodeoffset = 0;
-                       else
-                               cdrom_subcodeoffset = 128;
-                       for (i = 0; i < 100; i += 4) {
-                               put_long (subcode_address + cdrom_subcodeoffset, 0);
-                               cdrom_subcodeoffset += 4;
+       }
+
+       subcodecounter--;
+       if (subcodecounter <= 0) {
+               if ((cdrom_flags & CDFLAG_SUBCODE) && subcodebufferoffset != subcodebufferoffsetw) {
+                       uae_sem_wait (&sub_sem);
+                       if (subcodebufferinuse[subcodebufferoffset]) {
+                               if (cdrom_subcodeoffset >= 128)
+                                       cdrom_subcodeoffset = 0;
+                               else
+                                       cdrom_subcodeoffset = 128;
+                               // 96 byte subchannel data
+                               for (int i = 0; i < SUB_CHANNEL_SIZE; i++)
+                                       put_byte (subcode_address + cdrom_subcodeoffset + i, subcodebuffer[subcodebufferoffset * SUB_CHANNEL_SIZE + i]);
+                               put_long (subcode_address + cdrom_subcodeoffset + SUB_CHANNEL_SIZE, 0xffffffff);
+                               subcodebufferinuse[subcodebufferoffset] = 0;
+                               cdrom_subcodeoffset += 100;
+                               subcodebufferoffset++;
+                               if (subcodebufferoffset >= MAX_SUBCODEBUFFER)
+                                       subcodebufferoffset -= MAX_SUBCODEBUFFER;
+                               set_status (CDINTERRUPT_SUBCODE);
                        }
+                       uae_sem_post (&sub_sem);
                }
+               subcodecounter = 1000000 / (70 * 75 * cdrom_speed);
        }
 
        if (frame2counter > 0)
@@ -1248,17 +1279,12 @@ void AKIKO_hsync_handler (void)
        if (mediacheckcounter > 0)
                mediacheckcounter--;
 
-       if (cdrom_playing) {
-               if (cdrom_audiotimeout > 0) {
-                       cdrom_audiotimeout--;
-                       if (cdrom_audiotimeout == 0) {
-                               set_status (CDINTERRUPT_RXDMADONE);
-                               cdrom_playing = 0;
-                               cdrom_result_buffer[1] = 0;
-                               cdrom_start_return_data (2);
-                       }
-               }
+       if (cdrom_audiotimeout > 0) {
+               cdrom_audiotimeout--;
+               if (cdrom_audiotimeout == 0)
+                       cdrom_audiotimeout = -1;
        }
+
        akiko_internal ();
        akiko_handler ();
 }
@@ -1300,20 +1326,16 @@ static void *akiko_thread (void *null)
                }
 
                if (frame2counter <= 0) {
-                       uae_u8 *s;
                        frame2counter = 312 * 50 / 2;
-                       s = sys_command_cd_qcode (DF_IOCTL, unitnum);
-                       if (s) {
-                               uae_u8 as = s[1];
-                               memcpy (qcode_buf, s, sizeof qcode_buf);
+                       if (sys_command_cd_qcode (DF_IOCTL, unitnum, qcode_buf)) {
+                               uae_u8 as = qcode_buf[1];
                                qcode_valid = 1;
                                if (as == AUDIO_STATUS_IN_PROGRESS) {
-                                       int lsn = msf2lsn ((s[5 + 4] << 16) | (s[6 + 4] << 8) | (s[7 + 4] << 0));
-                                       //write_log("%d %d (%d %d)\n", lsn, msf2lsn (last_play_end) - lsn, cdrom_leadout, msf2lsn (last_play_end));
+                                       frame2counter /= 4;
+                                       int lsn = msf2lsn (fromlongbcd (qcode_buf + 4 + 7));
                                        // make sure audio play really ends because not all drives report position accurately
-                                       if ((lsn >= cdrom_leadout - 3 * 75 || lsn >= msf2lsn(last_play_end) - 3 * 75) && !cdrom_audiotimeout) {
+                                       if ((lsn >= cdrom_toc_cd_buffer.lastaddress - 3 * 75 || lsn >= last_play_end - 3 * 75) && cdrom_audiotimeout == 0) {
                                                cdrom_audiotimeout = 3 * 312;
-                                               //write_log("audiotimeout starts\n");
                                        }
                                }
                        }
@@ -1323,11 +1345,13 @@ static void *akiko_thread (void *null)
                        mediacheckcounter = 312 * 50 * 2;
                        int media = sys_command_ismedia (DF_IOCTL, unitnum, 1);
                        if (media < 0) {
-                               cd_hunt = 1;
-                               write_log (L"CD32: device unit %d lost\n", unitnum);
-                               media = lastmediastate = cdrom_disk = 0;
-                               mediachanged = 1;
-                               cdaudiostop_do ();
+                               if (!cd_hunt) {
+                                       cd_hunt = 1;
+                                       write_log (L"CD32: device unit %d lost\n", unitnum);
+                                       media = lastmediastate = cdrom_disk = 0;
+                                       mediachanged = 1;
+                                       cdaudiostop_do ();
+                               }
                        } else if (media != lastmediastate) {
                                write_log (L"CD32: media changed = %d (hunt=%d)\n", media, cd_hunt);
                                lastmediastate = cdrom_disk = media;
@@ -1353,7 +1377,7 @@ static void *akiko_thread (void *null)
                                while (offset < SECTOR_BUFFER_SIZE) {
                                        p = 0;
                                        if (sector < cdrom_data_end)
-                                               p = sys_command_cd_read (DF_IOCTL, unitnum, sector);
+                                               p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, sector, 1);
                                        if (p)
                                                memcpy (sector_buffer_2 + offset * 2048, p, 2048);
                                        sector_buffer_info_2[offset] = p ? 3 : 0;
@@ -1626,6 +1650,12 @@ static void akiko_bput2 (uaecptr addr, uae_u32 v, int msg)
                        cdrom_sector_counter = 0;
                if (!(cdrom_flags & CDFLAG_PBX) && (tmp & CDFLAG_PBX))
                        cdrom_pbx = 0;
+               if ((cdrom_flags & CDFLAG_SUBCODE) && !(tmp & CDFLAG_SUBCODE)) {
+                       uae_sem_wait (&sub_sem);
+                       memset (subcodebufferinuse, 0, sizeof subcodebufferinuse);
+                       subcodebufferoffset = subcodebufferoffsetw = 0;
+                       uae_sem_post (&sub_sem);
+               }
                break;
                } else if (addr < 0x30) {
                        break;
@@ -1737,7 +1767,7 @@ int akiko_init (void)
 {
        if (currprefs.cs_cd32cd && cdromok == 0) {
                unitnum = -1;
-               if (!device_func_init (DEVICE_TYPE_ANY)) {
+               if (!device_func_init (DEVICE_TYPE_IOCTL)) {
                        write_log (L"no CDROM support\n");
                        return 0;
                }
@@ -1752,6 +1782,7 @@ int akiko_init (void)
                }
        }
        uae_sem_init (&akiko_sem, 0, 1);
+       uae_sem_init (&sub_sem, 0, 1);
        if (!savestate_state) {
                cdrom_playing = cdrom_paused = 0;
                cdrom_data_offset = -1;
@@ -1808,16 +1839,16 @@ uae_u8 *save_akiko (int *len)
        save_u32 ((cdrom_playing ? 1 : 0) | (cdrom_paused ? 2 : 0) | (cdrom_disk ? 4 : 0));
        if (cdrom_playing)
                cd_qcode (0);
-       save_u32 (last_play_pos);
-       save_u32 (last_play_end);
+       save_u32 (lsn2msf (last_play_pos));
+       save_u32 (lsn2msf (last_play_end));
        save_u8 ((uae_u8)cdrom_toc_counter);
 
        save_u8 (cdrom_speed);
        save_u8 (cdrom_current_sector);
 
        save_u32 (cdrom_toc_crc);
-       save_u8 (cdrom_toc_entries);
-       save_u32 (cdrom_leadout);
+       save_u8 (cdrom_toc_cd_buffer.points);
+       save_u32 (cdrom_toc_cd_buffer.lastaddress);
 
        *len = dst - dstbak;
        return dstbak;
@@ -1876,8 +1907,8 @@ uae_u8 *restore_akiko (uae_u8 *src)
        if (v & 2)
                cdrom_paused = 1;
 
-       last_play_pos = restore_u32 ();
-       last_play_end = restore_u32 ();
+       last_play_pos = msf2lsn (restore_u32 ());
+       last_play_end = msf2lsn (restore_u32 ());
        cdrom_toc_counter = (uae_s8)restore_u8 ();
        cdrom_speed = restore_u8 ();
        cdrom_current_sector = (uae_s8)restore_u8 ();
@@ -1895,7 +1926,7 @@ void restore_akiko_finish (void)
                return;
        akiko_init ();
        akiko_c2p_do ();
-       cdrom_toc ();
+       get_cdrom_toc ();
        write_comm_pipe_u32 (&requests, 0x0102, 1); // pause
        write_comm_pipe_u32 (&requests, 0x0104, 1); // stop
        write_comm_pipe_u32 (&requests, 0x0103, 1); // unpause
index d5ed42bc6df0169232dab28a0c24791e8f057a8d..3179ba0302e6699ee75d45a1328071ac7d3897ee 100644 (file)
--- a/audio.cpp
+++ b/audio.cpp
@@ -64,7 +64,7 @@ static bool debugchannel (int ch)
 
 STATIC_INLINE bool usehacks (void)
 {
-       return currprefs.cpu_model >= 68020 && !currprefs.cpu_cycle_exact;
+       return currprefs.cpu_model >= 68020 || currprefs.m68k_speed != -1;
 }
 
 #define SINC_QUEUE_MAX_AGE 2048
@@ -1237,12 +1237,15 @@ static void audio_state_channel2 (int nr, bool perfin)
        }
        audio_activate ();
 
-       if ((cdp->state == 2 || cdp->state == 3) && (currprefs.cpu_model >= 68020 || currprefs.m68k_speed != 0) && !chan_ena && old_dma) {
+       if ((cdp->state == 2 || cdp->state == 3) && usehacks () && !chan_ena && old_dma) {
                // DMA switched off, state=2/3 and "too fast CPU": kill DMA instantly
                // or CPU timed DMA wait routines in common tracker players will lose notes
 #ifdef DEBUG_AUDIO
                write_log (L"%d: INSTADMAOFF\n", nr, M68K_GETPC);
 #endif
+               newsample (nr, (cdp->dat2 >> 0) & 0xff);
+               if (napnav)
+                       setirq (nr, 91);
                zerostate (nr);
                return;
        }
@@ -1258,10 +1261,18 @@ static void audio_state_channel2 (int nr, bool perfin)
                if (chan_ena) {
                        cdp->evtime = MAX_EV;
                        cdp->state = 1;
-                       cdp->dsr = true;
                        cdp->dr = true;
                        cdp->drhpos = hpos;
                        cdp->wlen = cdp->len;
+                       // too fast CPU and some tracker players: enable DMA, CPU delay, update AUDxPT with loop position
+                       if (usehacks ()) {
+                               // copy AUDxPT - 2 to internal latch instantly
+                               cdp->pt = cdp->lc - 2;
+                               cdp->dsr = false;
+                       } else {
+                               // normal hardware behavior: latch it after first DMA fetch comes
+                               cdp->dsr = true;
+                       }
 #ifdef TEST_AUDIO
                        cdp->have_dat = false;
 #endif
@@ -1273,7 +1284,7 @@ static void audio_state_channel2 (int nr, bool perfin)
                        cdp->state = 2;
                        setirq (nr, 0);
                        loaddat (nr);
-                       if (currprefs.cpu_model >= 68020 && !currprefs.cpu_cycle_exact && cdp->per < 10 * CYCLE_UNIT) {
+                       if (usehacks () && cdp->per < 10 * CYCLE_UNIT) {
                                // make sure audio.device AUDxDAT startup returns to idle state before DMA is enabled
                                newsample (nr, (cdp->dat2 >> 0) & 0xff);
                                zerostate (nr);
index a4bd8b6d1eb65731eb57f71aa48c4f63009233cb..5369750e9764f0f24fdbbd6c2e3165af6c0b22da 100644 (file)
 #include "scsidev.h"
 #include "savestate.h"
 
+static int scsiemu;
+
 static struct device_functions *device_func[2];
 static int have_ioctl;
 static int openlist[MAX_TOTAL_DEVICES];
 static int forcedunit = -1;
 
+/* convert minutes, seconds and frames -> logical sector number */
+int msf2lsn (int msf)
+{
+       int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff));
+       sector -= 150;
+       return sector;
+}
+
+/* convert logical sector number -> minutes, seconds and frames */
+int lsn2msf (int sectors)
+{
+       int msf;
+       sectors += 150;
+       msf = (sectors / (75 * 60)) << 16;
+       msf |= ((sectors / 75) % 60) << 8;
+       msf |= (sectors % 75) << 0;
+       return msf;
+}
+
+uae_u8 frombcd (uae_u8 v)
+{
+       return (v >> 4) * 10 + (v & 15);
+}
+uae_u8 tobcd (uae_u8 v)
+{
+       return ((v / 10) << 4) | (v % 10);
+}
+int fromlongbcd (uae_u8 *p)
+{
+       return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2])  << 0);
+}
+void tolongbcd (uae_u8 *p, int v)
+{
+       p[0] = tobcd ((v >> 16) & 0xff);
+       p[1] = tobcd ((v >> 8) & 0xff);
+       p[2] = tobcd ((v >> 0) & 0xff);
+}
+
 #ifdef _WIN32
 
 #include "od-win32/win32.h"
@@ -30,26 +70,29 @@ extern struct device_functions devicefunc_cdimage;
 
 static void install_driver (int flags)
 {
-       int installed = 0;
-
+       scsiemu = 0;
        device_func[DF_IOCTL] = NULL;
-       device_func[DF_SCSI] = &devicefunc_win32_aspi;
+       device_func[DF_SCSI] = NULL;
        if (devicefunc_cdimage.checkbus (flags | DEVICE_TYPE_CHECKAVAIL)) {
                device_func[DF_IOCTL] = &devicefunc_cdimage;
-               device_func[DF_SCSI] = NULL;
+               device_func[DF_SCSI] = &devicefunc_cdimage;
+               scsiemu = 1;
                return;
        }
 #ifdef WINDDK
        if (!device_func[DF_IOCTL])
                device_func[DF_IOCTL] = &devicefunc_win32_ioctl;
-       device_func[DF_SCSI] = &devicefunc_win32_spti;
-       installed = 1;
-       if (currprefs.win32_uaescsimode == UAESCSI_ADAPTECASPI ||
-               currprefs.win32_uaescsimode == UAESCSI_NEROASPI ||
-               currprefs.win32_uaescsimode == UAESCSI_FROGASPI ||
-               !installed) {
-                       device_func[DF_SCSI] = &devicefunc_win32_aspi;
-                       device_func[DF_IOCTL] = 0;
+       if (currprefs.win32_uaescsimode == UAESCSI_CDEMU) {
+               device_func[DF_SCSI] = &devicefunc_win32_ioctl;
+               scsiemu = 1;
+       } else if (flags != DEVICE_TYPE_IOCTL) {
+               device_func[DF_SCSI] = &devicefunc_win32_spti;
+               if (currprefs.win32_uaescsimode == UAESCSI_ADAPTECASPI ||
+                       currprefs.win32_uaescsimode == UAESCSI_NEROASPI ||
+                       currprefs.win32_uaescsimode == UAESCSI_FROGASPI) {
+                               device_func[DF_SCSI] = &devicefunc_win32_aspi;
+                               device_func[DF_IOCTL] = 0;
+               }
        }
 #endif
        if (device_func[DF_SCSI])
@@ -108,8 +151,20 @@ void device_func_reset (void)
 
 int device_func_init (int flags)
 {
+       static int old_flags = -1;
        int support_scsi = 0, support_ioctl = 0;
-       int oflags = (flags & DEVICE_TYPE_SCSI) ? 0 : (1 << INQ_ROMD);
+       int oflags;
+       
+       if (flags & DEVICE_TYPE_USE_OLD) {
+               if (old_flags >= 0)
+                       flags = old_flags;
+               else
+                       flags &= ~DEVICE_TYPE_USE_OLD;
+       }
+
+       old_flags = flags;
+
+       oflags = (flags & DEVICE_TYPE_SCSI) ? 0 : (1 << INQ_ROMD);
 
        forcedunit = -1;
        install_driver (flags);
@@ -119,8 +174,12 @@ int device_func_init (int flags)
                have_ioctl = 0;
        if (flags & DEVICE_TYPE_ALLOWEMU)
                oflags |= DEVICE_TYPE_ALLOWEMU;
-       if (device_func[DF_SCSI])
-               support_scsi = device_func[DF_SCSI]->openbus (oflags) ? 1 : 0;
+       if (device_func[DF_SCSI]) {
+               if (device_func[DF_SCSI] != device_func[DF_IOCTL])
+                       support_scsi = device_func[DF_SCSI]->openbus (oflags) ? 1 : 0;
+               else
+                       support_scsi = 1;
+       }
        oflags |= 1 << INQ_ROMD;
        if (have_ioctl)
                support_ioctl = device_func[DF_IOCTL]->openbus (oflags) ? 1 : 0;
@@ -165,8 +224,36 @@ void sys_command_cd_stop (int mode, int unitnum)
        device_func[DF_IOCTL]->stop (unitnum);
 }
 
+#if 0
+static int adjustplaypos (int unitnum, int startlsn)
+{
+       uae_u8 q[SUBQ_SIZE];
+       if (!device_func[DF_IOCTL]->qcode (unitnum, q, startlsn - 1))
+               return startlsn;
+       int otrack = frombcd (q[4 + 1]);
+       int lsn = startlsn;
+       int max = 150;
+       while (max-- > 0 && startlsn > 0) {
+               if (!device_func[DF_IOCTL]->qcode (unitnum, q, startlsn - 1))
+                       break;
+               int track = frombcd (q[4 + 1]);
+               int idx = frombcd (q[4 + 2]);
+               //write_log (L"%d %d\n", track, idx);
+               if (idx != 0 || otrack != track)
+                       break;
+               startlsn--;
+       }
+       if (lsn != startlsn)
+               write_log (L"CD play adjust %d -> %d\n", lsn, startlsn);
+       startlsn -= 10;
+       if (startlsn < 0)
+               startlsn = 0;
+       return startlsn;
+}
+#endif
+
 /* play CD audio */
-int sys_command_cd_play (int mode, int unitnum,uae_u32 startmsf, uae_u32 endmsf, int scan)
+int sys_command_cd_play (int mode, int unitnum, int startlsn, int endlsn, int scan)
 {
        if (mode == DF_SCSI || !have_ioctl) {
                uae_u8 cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
@@ -180,6 +267,8 @@ int sys_command_cd_play (int mode, int unitnum,uae_u32 startmsf, uae_u32 endmsf,
                        cmd[9] = 0x40;
                } else {
 #endif
+                       int startmsf = lsn2msf (startlsn);
+                       int endmsf = lsn2msf (endlsn);
                        cmd[0] = 0x47;
                        cmd[3] = (uae_u8)(startmsf >> 16);
                        cmd[4] = (uae_u8)(startmsf >> 8);
@@ -192,7 +281,17 @@ int sys_command_cd_play (int mode, int unitnum,uae_u32 startmsf, uae_u32 endmsf,
 #endif
                return device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd)) == 0 ? 0 : 1;
        }
-       return device_func[DF_IOCTL]->play (unitnum, startmsf, endmsf, scan);
+       //startlsn = adjustplaypos (unitnum, startlsn);
+       return device_func[DF_IOCTL]->play (unitnum, startlsn, endlsn, scan, NULL);
+}
+
+/* play CD audio with subchannels */
+int sys_command_cd_play (int mode, int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc)
+{
+       if (mode == DF_SCSI || !have_ioctl)
+               return 0;
+       //startlsn = adjustplaypos (unitnum, startlsn);
+       return device_func[DF_IOCTL]->play (unitnum, startlsn, endlsn, scan, subfunc);
 }
 
 /* set CD audio volume */
@@ -204,68 +303,83 @@ void sys_command_cd_volume (int mode, int unitnum, uae_u16 volume)
 }
 
 /* read qcode */
-uae_u8 *sys_command_cd_qcode (int mode, int unitnum)
+int sys_command_cd_qcode (int mode, int unitnum, uae_u8 *buf)
 {
        if (mode == DF_SCSI || !have_ioctl) {
                uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,(uae_u8)(DEVICE_SCSI_BUFSIZE>>8),(uae_u8)(DEVICE_SCSI_BUFSIZE&0xff),0};
-               return  device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               if (p) {
+                       memcpy (buf, p, SUBQ_SIZE);
+                       return 1;
+               }
+               return 0; 
        }
-       return device_func[DF_IOCTL]->qcode (unitnum);
+       return device_func[DF_IOCTL]->qcode (unitnum, buf, -1);
 };
 
 /* read table of contents */
-uae_u8 *sys_command_cd_toc (int mode, int unitnum)
+struct cd_toc_head *sys_command_cd_toc (int mode, int unitnum)
 {
        if (mode == DF_SCSI || !have_ioctl) {
                uae_u8 cmd [10] = { 0x43,0,2,0,0,0,1,(uae_u8)(DEVICE_SCSI_BUFSIZE>>8),(uae_u8)(DEVICE_SCSI_BUFSIZE&0xff),0};
-               return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof(cmd), 0);
+               return NULL;
+//             return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof(cmd), 0);
        }
        return device_func[DF_IOCTL]->toc (unitnum);
 }
 
 /* read one cd sector */
-uae_u8 *sys_command_cd_read (int mode, int unitnum, int offset)
+uae_u8 *sys_command_cd_read (int mode, int unitnum, uae_u8 *data, int block, int size)
 {
        if (mode == DF_SCSI || !have_ioctl) {
                uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 };
-               cmd[3] = (uae_u8)(offset >> 16);
-               cmd[4] = (uae_u8)(offset >> 8);
-               cmd[5] = (uae_u8)(offset >> 0);
-               return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               cmd[3] = (uae_u8)(block >> 16);
+               cmd[4] = (uae_u8)(block >> 8);
+               cmd[5] = (uae_u8)(block >> 0);
+               uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               if (p && data)
+                       memcpy (data, p, size);
+               return p;
        }
-       return device_func[DF_IOCTL]->read (unitnum, offset);
+       return device_func[DF_IOCTL]->read (unitnum, data, block, size);
 }
-uae_u8 *sys_command_cd_rawread (int mode, int unitnum, int offset, int size)
+uae_u8 *sys_command_cd_rawread (int mode, int unitnum, uae_u8 *data, int sector, int size, int sectorsize)
 {
        if (mode == DF_SCSI || !have_ioctl) {
-               uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 };
-               cmd[3] = (uae_u8)(offset >> 16);
-               cmd[4] = (uae_u8)(offset >> 8);
-               cmd[5] = (uae_u8)(offset >> 0);
-               return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, size, 0x10, 0, 0 };
+               cmd[3] = (uae_u8)(sector >> 16);
+               cmd[4] = (uae_u8)(sector >> 8);
+               cmd[5] = (uae_u8)(sector >> 0);
+               uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               if (p && data)
+                       memcpy (data, p, size);
+               return p;
        }
-       return device_func[DF_IOCTL]->rawread (unitnum, offset, size);
+       return device_func[DF_IOCTL]->rawread (unitnum, data, sector, size, sectorsize);
 }
 
 /* read block */
-uae_u8 *sys_command_read (int mode, int unitnum, int offset)
+uae_u8 *sys_command_read (int mode, int unitnum, uae_u8 *data, int block, int size)
 {
        if (mode == DF_SCSI || !have_ioctl) {
                uae_u8 cmd[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
-               cmd[2] = (uae_u8)(offset >> 24);
-               cmd[3] = (uae_u8)(offset >> 16);
-               cmd[4] = (uae_u8)(offset >> 8);
-               cmd[5] = (uae_u8)(offset >> 0);
-               return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               cmd[2] = (uae_u8)(block >> 24);
+               cmd[3] = (uae_u8)(block >> 16);
+               cmd[4] = (uae_u8)(block >> 8);
+               cmd[5] = (uae_u8)(block >> 0);
+               uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+               if (p && data)
+                       memcpy (data, p, size);
+               return p;
        }
-       return device_func[DF_IOCTL]->read (unitnum, offset);
+       return device_func[DF_IOCTL]->read (unitnum, data, block, size);
 }
 
 /* write block */
-int sys_command_write (int mode, int unitnum, int offset)
+int sys_command_write (int mode, int unitnum, uae_u8 *data, int offset, int size)
 {
        if (mode == DF_SCSI || !have_ioctl) {
-               uae_u8 cmd[10] = { 0x2a, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
+               uae_u8 cmd[10] = { 0x2a, 0, 0, 0, 0, 0, 0, 0, size, 0 };
                cmd[2] = (uae_u8)(offset >> 24);
                cmd[3] = (uae_u8)(offset >> 16);
                cmd[4] = (uae_u8)(offset >> 8);
@@ -274,7 +388,7 @@ int sys_command_write (int mode, int unitnum, int offset)
                        return -1;
                return 0;
        }
-       return device_func[DF_IOCTL]->write (unitnum, offset);
+       return device_func[DF_IOCTL]->write (unitnum, data, offset, size);
 }
 
 int sys_command_ismedia (int mode, int unitnum, int quick)
@@ -290,7 +404,7 @@ int sys_command_ismedia (int mode, int unitnum, int quick)
                if (quick)
                        return -1;
                memset(&di, 0, sizeof di);
-               if (device_func[DF_SCSI]->info (unitnum, &di) == NULL)
+               if (device_func[DF_SCSI]->info (unitnum, &di, quick) == NULL, quick)
                        return -1;
                return di.media_inserted;
        } else {
@@ -298,12 +412,12 @@ int sys_command_ismedia (int mode, int unitnum, int quick)
        }
 }
 
-struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di)
+struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di, int quick)
 {
        if (mode == DF_SCSI || !have_ioctl)
-               return device_func[DF_SCSI]->info (unitnum, di);
+               return device_func[DF_SCSI]->info (unitnum, di, quick);
        else
-               return device_func[DF_IOCTL]->info (unitnum, di);
+               return device_func[DF_IOCTL]->info (unitnum, di, quick);
 }
 
 struct device_scsi_info *sys_command_scsi_info (int mode, int unitnum, struct device_scsi_info *dsi)
@@ -403,50 +517,6 @@ static void scsi_atapi_fixup_inquiry (struct amigascsi *as)
        }
 }
 
-int sys_command_scsi_direct_native(int unitnum, struct amigascsi *as)
-{
-       int ret = device_func[DF_SCSI]->exec_direct (unitnum, as);
-       if (!ret && device_func[DF_SCSI]->isatapi(unitnum))
-               scsi_atapi_fixup_inquiry (as);
-       return ret;
-}
-
-int sys_command_scsi_direct (int unitnum, uaecptr acmd)
-{
-       int ret, i;
-       struct amigascsi as;
-       uaecptr ap;
-       addrbank *bank;
-
-       ap = get_long (acmd + 0);
-       as.len = get_long (acmd + 4);
-
-       bank = &get_mem_bank (ap);
-       if (!bank || !bank->check(ap, as.len))
-               return -5;
-       as.data = bank->xlateaddr (ap);
-
-       ap = get_long (acmd + 12);
-       as.cmd_len = get_word (acmd + 16);
-       for (i = 0; i < as.cmd_len; i++)
-               as.cmd[i] = get_byte (ap++);
-       as.flags = get_byte (acmd + 20);
-       as.sense_len = get_word (acmd + 26);
-
-       ret = sys_command_scsi_direct_native (unitnum, &as);
-
-       put_long (acmd + 8, as.actual);
-       put_word (acmd + 18, as.cmdactual);
-       put_byte (acmd + 21, as.status);
-       put_word (acmd + 28, as.sactual);
-
-       ap = get_long (acmd + 22);
-       for (i = 0; i < as.sactual; i++)
-               put_byte (ap, as.sensedata[i]);
-
-       return ret;
-}
-
 void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen)
 {
        int i;
@@ -510,3 +580,457 @@ uae_u8 *restore_cd (int unit, uae_u8 *src)
        return src;
 }
 
+static bool nodisk (struct device_info *di)
+{
+       return di->media_inserted == 0;
+}
+static uae_u64 cmd_readx (int unitnum, uae_u8 *dataptr, int offset, int len)
+{
+       if (device_func[DF_IOCTL]->read (unitnum, dataptr, offset, len))
+               return len;
+       else
+               return 0;
+}
+
+static void wl (uae_u8 *p, int v)
+{
+       p[0] = v >> 24;
+       p[1] = v >> 16;
+       p[2] = v >> 8;
+       p[3] = v;
+}
+static void ww (uae_u8 *p, int v)
+{
+       p[0] = v >> 8;
+       p[1] = v;
+}
+static int rl (uae_u8 *p)
+{
+       return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
+}
+
+static struct cd_toc *gettoc (struct device_info *di, int block)
+{
+       for (int i = di->toc.first_track_offset; i < di->toc.last_track_offset; i++) {
+               struct cd_toc *t = &di->toc.toc[i];
+               if (t->paddress > block) {
+                       if (t->point == 1)
+                               return t;
+                       return t - 1;
+               }
+       }
+       return &di->toc.toc[di->toc.last_track_offset];
+}
+
+static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
+       uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
+{
+       uae_u64 len, offset;
+       int lr = 0, ls = 0;
+       int scsi_len = -1;
+       int status = 0;
+       int i;
+       char *ss;
+       struct device_info di;
+
+       *reply_len = *sense_len = 0;
+       memset (r, 0, 256);
+       memset (s, 0, 256);
+
+       sys_command_info (DF_IOCTL, unitnum, &di, 1);
+
+       if (cmdbuf[0] == 0) { /* TEST UNIT READY */
+               if (nodisk (&di))
+                       goto nodisk;
+               scsi_len = 0;
+               goto end;
+       }
+               
+       switch (cmdbuf[0])
+       {
+       case 0x12: /* INQUIRY */
+               if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
+                       goto err;
+               len = cmdbuf[4];
+               if (cmdbuf[1] >> 5)
+                       goto err;
+               r[0] = 5; // CDROM
+               r[1] |= 0x80; // removable
+               r[2] = 2; /* supports SCSI-2 */
+               r[3] = 2; /* response data format */
+               r[4] = 32; /* additional length */
+               r[7] = 0x20; /* 16 bit bus */
+               scsi_len = lr = len < 36 ? (uae_u32)len : 36;
+               r[2] = 2;
+               r[3] = 2;
+               ss = "UAE";
+               i = 0; /* vendor id */
+               while (i < 8 && ss[i]) {
+                       r[8 + i] = ss[i];
+                       i++;
+               }
+               while (i < 8) {
+                       r[8 + i] = 32;
+                       i++;
+               }
+               char tmp[256];
+               sprintf (tmp, "SCSI CD%d EMU", unitnum);
+               ss = tmp;
+               i = 0; /* product id */
+               while (i < 16 && ss[i]) {
+                       r[16 + i] = ss[i];
+                       i++;
+               }
+               while (i < 16) {
+                       r[16 + i] = 32;
+                       i++;
+               }
+               ss = "0.1";
+               i = 0; /* product revision */
+               while (i < 4 && ss[i]) {
+                       r[32 + i] = ss[i];
+                       i++;
+               }
+               while (i < 4) {
+                       r[32 + i] = 32;
+                       i++;
+               }
+               break;
+       case 0x1a: /* MODE SENSE(6) */
+               {
+                       uae_u8 *p;
+                       int pc = cmdbuf[2] >> 6;
+                       int pcode = cmdbuf[2] & 0x3f;
+                       int dbd = cmdbuf[1] & 8;
+                       int cyl, cylsec, head, tracksec;
+                       if (nodisk (&di))
+                               goto nodisk;
+                       cyl = di.cylinders;
+                       head = 1;
+                       cylsec = tracksec = di.trackspercylinder;
+                       //write_log (L"MODE SENSE PC=%d CODE=%d DBD=%d\n", pc, pcode, dbd);
+                       p = r;
+                       p[0] = 4 - 1;
+                       p[1] = 0;
+                       p[2] = 0;
+                       p[3] = 0;
+                       p += 4;
+                       if (!dbd) {
+                               uae_u32 blocks = di.sectorspertrack * di.cylinders * di.trackspercylinder;
+                               p[-1] = 8;
+                               wl(p + 0, blocks);
+                               wl(p + 4, di.bytespersector);
+                               p += 8;
+                       }
+                       if (pcode == 0) {
+                               p[0] = 0;
+                               p[1] = 0;
+                               p[2] = 0x20;
+                               p[3] = 0;
+                               r[0] += 4;
+                       } else if (pcode == 3) {
+                               p[0] = 3;
+                               p[1] = 24;
+                               p[3] = 1;
+                               p[10] = tracksec >> 8;
+                               p[11] = tracksec;
+                               p[12] = di.bytespersector >> 8;
+                               p[13] = di.bytespersector;
+                               p[15] = 1; // interleave
+                               p[20] = 0x80;
+                               r[0] += p[1];
+                       } else if (pcode == 4) {
+                               p[0] = 4;
+                               wl(p + 1, cyl);
+                               p[1] = 24;
+                               p[5] = head;
+                               wl(p + 13, cyl);
+                               ww(p + 20, 0);
+                               r[0] += p[1];
+                       } else {
+                               goto err;
+                       }
+                       r[0] += r[3];
+                       scsi_len = lr = r[0] + 1;
+                       break;
+               }
+               break;
+       case 0x1d: /* SEND DIAGNOSTICS */
+               scsi_len = 0;
+               break;
+       case 0x25: /* READ_CAPACITY */
+               {
+                       int pmi = cmdbuf[8] & 1;
+                       uae_u32 lba = (cmdbuf[2] << 24) | (cmdbuf[3] << 16) | (cmdbuf[4] << 8) | cmdbuf[5];
+                       int cyl, cylsec, head, tracksec;
+                       if (nodisk (&di))
+                               goto nodisk;
+                       uae_u32 blocks = di.sectorspertrack * di.cylinders * di.trackspercylinder;
+                       cyl = di.cylinders;
+                       head = 1;
+                       cylsec = tracksec = di.trackspercylinder;
+                       if (pmi == 0 && lba != 0)
+                               goto errreq;
+                       if (pmi) {
+                               lba += tracksec * head;
+                               lba /= tracksec * head;
+                               lba *= tracksec * head;
+                               if (lba > blocks)
+                                       lba = blocks;
+                               blocks = lba;
+                       }
+                       wl (r, blocks);
+                       wl (r + 4, di.bytespersector);
+                       scsi_len = lr = 8;
+               }
+               break;
+       case 0x08: /* READ (6) */
+       {
+               if (nodisk (&di))
+                       goto nodisk;
+               offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
+               struct cd_toc *t = gettoc (&di, offset);
+               if ((t->control & 0x0c) == 0x04) {
+                       len = cmdbuf[4];
+                       if (!len)
+                               len = 256;
+                       scsi_len = (uae_u32)cmd_readx (unitnum, scsi_data, offset, len) * di.bytespersector;;
+               } else {
+                       goto notdatatrack;
+               }
+       }
+       break;
+       case 0x0a: /* WRITE (6) */
+               goto readprot;
+       case 0x28: /* READ (10) */
+       {
+               if (nodisk (&di))
+                       goto nodisk;
+               offset = rl (cmdbuf + 2);
+               struct cd_toc *t = gettoc (&di, offset);
+               if ((t->control & 0x0c) == 0x04) {
+                       len = rl (cmdbuf + 7 - 2) & 0xffff;
+                       scsi_len = cmd_readx (unitnum, scsi_data, offset, len) * di.bytespersector;
+               } else {
+                       goto notdatatrack;
+               }
+       }
+       break;
+       case 0x2a: /* WRITE (10) */
+               goto readprot;
+       case 0xa8: /* READ (12) */
+       {
+               if (nodisk (&di))
+                       goto nodisk;
+               offset = rl (cmdbuf + 2);
+               struct cd_toc *t = gettoc (&di, offset);
+               if ((t->control & 0x0c) == 0x04) {
+                       len = rl (cmdbuf + 6);
+                       scsi_len = (uae_u32)cmd_readx (unitnum, scsi_data, offset, len) * di.bytespersector;;
+               } else {
+                       goto notdatatrack;
+               }
+       }
+       break;
+       case 0xaa: /* WRITE (12) */
+               goto readprot;
+       case 0x43: // READ TOC
+               {
+                       uae_u8 *p = scsi_data;
+                       int strack = cmdbuf[6];
+                       int msf = cmdbuf[1] & 2;
+                       int maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
+                       struct cd_toc_head *toc = sys_command_cd_toc (DF_IOCTL, unitnum);
+                       if (!toc)
+                               goto readerr;
+                       if (maxlen < 4)
+                               goto errreq;
+                       if (strack == 0)
+                               strack = toc->first_track;
+                       if (strack >= 100 && strack != 0xaa)
+                               goto errreq;
+                       if (strack == 0xaa)
+                               strack = 0xa2;
+                       uae_u8 *p2 = p + 4;
+                       p[2] = 0;
+                       p[3] = 0;
+                       for (int i = 0; i < toc->points; i++) {
+                               if (strack == toc->toc[i].point) {
+                                       int trk = strack >= 100 ? 0xaa : strack;
+                                       if (p[2] == 0)
+                                               p[2] = trk;
+                                       p[3] = trk;
+                                       int addr = toc->toc[i].paddress;
+                                       if (msf)
+                                               addr = lsn2msf (addr);
+                                       if (p2 - p + 8 > maxlen)
+                                               goto errreq;
+                                       p2[0] = 0;
+                                       p2[1] = (toc->toc[i].adr << 4) | toc->toc[i].control;
+                                       p2[2] = trk;
+                                       p2[3] = 0;
+                                       p2[4] = addr >> 24;
+                                       p2[5] = addr >> 16;
+                                       p2[6] = addr >>  8;
+                                       p2[7] = addr >>  0;
+                                       p2 += 8;
+                                       strack++;
+                               }
+                               if (i == toc->points - 1) {
+                                       if (strack >= 0xa2)
+                                               break;
+                                       i = 0;
+                                       strack = 0xa2;
+                               }
+                       }
+                       int tlen = p2 - (p + 4);
+                       p[0] = tlen >> 8;
+                       p[1] = tlen >> 0;
+                       scsi_len = tlen + 4;
+               }
+               break;
+readprot:
+               status = 2; /* CHECK CONDITION */
+               s[0] = 0x70;
+               s[2] = 7; /* DATA PROTECT */
+               s[12] = 0x27; /* WRITE PROTECTED */
+               ls = 12;
+               break;
+nodisk:
+               status = 2; /* CHECK CONDITION */
+               s[0] = 0x70;
+               s[2] = 2; /* NOT READY */
+               s[12] = 0x3A; /* MEDIUM NOT PRESENT */
+               ls = 12;
+               break;
+readerr:
+               status = 2; /* CHECK CONDITION */
+               s[0] = 0x70;
+               s[2] = 2; /* NOT READY */
+               s[12] = 0x11; /* UNRECOVERED READ ERROR */
+               ls = 12;
+               break;
+notdatatrack:
+               status = 2;
+               s[0] = 0x70;
+               s[2] = 5;
+               s[12] = 0x64; /* ILLEGAL MODE FOR THIS TRACK */
+               ls = 12;
+               break;
+
+       default:
+err:
+               write_log (L"CDEMU: unsupported scsi command 0x%02X\n", cmdbuf[0]);
+errreq:
+               lr = -1;
+               status = 2; /* CHECK CONDITION */
+               s[0] = 0x70;
+               s[2] = 5; /* ILLEGAL REQUEST */
+               s[12] = 0x24; /* ILLEGAL FIELD IN CDB */
+               ls = 12;
+               break;
+       }
+end:
+       *data_len = scsi_len;
+       *reply_len = lr;
+       *sense_len = ls;
+       return status;
+}
+
+static int execscsicmd_direct (int unitnum, struct amigascsi *as)
+{
+       int sactual = 0;
+       int io_error = 0;
+       uae_u8 *scsi_datap, *scsi_datap_org;
+       uae_u32 scsi_cmd_len_orig = as->cmd_len;
+       uae_u8 cmd[16];
+       uae_u8 replydata[256];
+       int datalen = as->len;
+       int senselen = as->sense_len;
+       int replylen = 0;
+
+       memcpy (cmd, as->cmd, as->cmd_len);
+       scsi_datap = scsi_datap_org = as->len ? as->data : 0;
+       if (as->sense_len > 32)
+               as->sense_len = 32;
+
+       as->status = scsi_emulate (unitnum, cmd, as->cmd_len, scsi_datap, &datalen, replydata, &replylen, as->sensedata, &senselen);
+
+       as->cmdactual = as->status == 0 ? 0 : as->cmd_len; /* fake scsi_CmdActual */
+       if (as->status) {
+               io_error = 45; /* HFERR_BadStatus */
+               as->sense_len = senselen;
+               as->actual = 0; /* scsi_Actual */
+       } else {
+               int i;
+               if (replylen > 0) {
+                       for (i = 0; i < replylen; i++)
+                               scsi_datap[i] = replydata[i];
+                       datalen = replylen;
+               }
+               for (i = 0; i < as->sense_len; i++)
+                       as->sensedata[i] = 0;
+               sactual = 0;
+               if (datalen < 0) {
+                       io_error = 20; /* io_Error, but not specified */
+                       as->actual = 0; /* scsi_Actual */
+               } else {
+                       as->len = datalen;
+                       io_error = 0;
+                       as->actual = as->len; /* scsi_Actual */
+               }
+       }
+       as->sactual = sactual;
+
+       return io_error;
+}
+
+int sys_command_scsi_direct_native (int unitnum, struct amigascsi *as)
+{
+       if (scsiemu) {
+               return execscsicmd_direct (unitnum, as);
+       } else {
+               if (!device_func[DF_SCSI] || !device_func[DF_SCSI]->exec_direct)
+                       return -1;
+       }
+       int ret = device_func[DF_SCSI]->exec_direct (unitnum, as);
+       if (!ret && device_func[DF_SCSI]->isatapi(unitnum))
+               scsi_atapi_fixup_inquiry (as);
+       return ret;
+}
+
+int sys_command_scsi_direct (int unitnum, uaecptr acmd)
+{
+       int ret, i;
+       struct amigascsi as;
+       uaecptr ap;
+       addrbank *bank;
+
+       ap = get_long (acmd + 0);
+       as.len = get_long (acmd + 4);
+
+       bank = &get_mem_bank (ap);
+       if (!bank || !bank->check(ap, as.len))
+               return -5;
+       as.data = bank->xlateaddr (ap);
+
+       ap = get_long (acmd + 12);
+       as.cmd_len = get_word (acmd + 16);
+       for (i = 0; i < as.cmd_len; i++)
+               as.cmd[i] = get_byte (ap++);
+       as.flags = get_byte (acmd + 20);
+       as.sense_len = get_word (acmd + 26);
+
+       ret = sys_command_scsi_direct_native (unitnum, &as);
+
+       put_long (acmd + 8, as.actual);
+       put_word (acmd + 18, as.cmdactual);
+       put_byte (acmd + 21, as.status);
+       put_word (acmd + 28, as.sactual);
+
+       ap = get_long (acmd + 22);
+       for (i = 0; i < as.sactual; i++)
+               put_byte (ap, as.sensedata[i]);
+
+       return ret;
+}
index afe857a954a131d0b901e2e007691468a7e3214a..1d0396a0338cd8c1a8eaad62113e081db251fad0 100644 (file)
 #include "fsdb.h"
 #include "threaddep/thread.h"
 #include "scsidev.h"
+#include <mp3decoder.h>
+#include <memory.h>
 #ifdef RETROPLATFORM
 #include "rp.h"
 #endif
 
+#define scsi_log write_log
+
 #define USE 1
 
 #define CDDA_BUFFERS 6
@@ -35,63 +39,59 @@ struct cdtoc
 {
        struct zfile *handle;
        int offset;
-       int filesize;
        uae_u8 *data;
+       struct zfile *subhandle;
+       int suboffset;
+       uae_u8 *subdata;
+
+       int filesize;
        TCHAR *fname;
        int address;
        uae_u8 adr, ctrl;
        int track;
        int size;
        int mp3;
+       int subcode;
 };
 
-static uae_u8 buffer[2352];
-static struct cdtoc toc[102];
-static int tracks;
-static uae_u64 cdsize;
-
-static int cdda_play_finished;
-static int cdda_play;
-static int cdda_paused;
-static int cdda_volume;
-static int cdda_volume_main;
-static uae_u32 cd_last_pos;
-static int cdda_start, cdda_end;
-
-static int imagechange;
-static int donotmountme;
-static TCHAR newfile[MAX_DPATH];
-
-/* convert minutes, seconds and frames -> logical sector number */
-static int msf2lsn (int        msf)
-{
-       int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff));
-       sector -= 150;
-       return sector;
-}
+struct cdunit {
+       bool enabled;
+       uae_u8 buffer[2352];
+       struct cdtoc toc[102];
+       int tracks;
+       uae_u64 cdsize;
+       int blocksize;
+
+       int cdda_play_finished;
+       int cdda_play;
+       int cdda_paused;
+       int cdda_volume;
+       int cdda_volume_main;
+       int cd_last_pos;
+       int cdda_start, cdda_end;
+       play_subchannel_callback cdda_subfunc;
+
+       int imagechange;
+       int donotmountme;
+       TCHAR newfile[MAX_DPATH];
+       uae_sem_t sub_sem;
+};
 
-/* convert logical sector number -> minutes, seconds and frames */
-static int lsn2msf (int        sectors)
-{
-       int msf;
-       sectors += 150;
-       msf = (sectors / (75 * 60)) << 16;
-       msf |= ((sectors / 75) % 60) << 8;
-       msf |= (sectors % 75) << 0;
-       return msf;
-}
+static struct cdunit cdunits[MAX_TOTAL_DEVICES];
 
-static struct cdtoc *findtoc (int *sectorp)
+static struct cdtoc *findtoc (struct cdunit *cdu, int *sectorp)
 {
        int i;
        int sector;
 
        sector = *sectorp;
-       for (i = 0; i <= tracks; i++) {
-               struct cdtoc *t = &toc[i];
+       for (i = 0; i <= cdu->tracks; i++) {
+               struct cdtoc *t = &cdu->toc[i];
                if (t->address > sector) {
-                       if (i == 0)
-                               return NULL;
+                       if (i == 0) {
+                               *sectorp = 0;
+                               return t;
+                       }
                        t--;
                        sector -= t->address;
                        *sectorp = sector;
@@ -101,216 +101,8 @@ static struct cdtoc *findtoc (int *sectorp)
        return NULL;
 }
 
-
-static int mp3_bitrates[] = {
-  0,  32,  64,  96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1,
-  0,  32,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, -1,
-  0,  32,  40,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, -1,
-  0,  32,  48,  56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, -1,
-  0,   8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, -1
-};
-static int mp3_frequencies[] = {
-       44100, 48000, 32000, 0,
-       22050, 24000, 16000, 0,
-       11025, 12000,  8000, 0
-};
-static int mp3_samplesperframe[] = {
-        384,  384,  384,
-       1152, 1152, 1152,
-       1152,  576,  576
-};
-
-static uae_u32 mp3decoder_getsize (struct zfile *zf)
-{
-       uae_u32 size;
-       int frames;
-
-       frames = 0;
-       size = 0;
-       for (;;) {
-               int ver, layer, bitrate, freq, padding, bitindex, iscrc;
-               int samplerate, framelen, bitrateidx, channelmode;
-               int isstereo;
-               uae_u8 header[4];
-
-               if (zfile_fread (header, sizeof header, 1, zf) != 1)
-                       return size;
-               if (header[0] != 0xff || ((header[1] & (0x80 | 0x40 | 0x20)) != (0x80 | 0x40 | 0x20))) {
-                       zfile_fseek (zf, -3, SEEK_CUR);
-                       continue;
-               }
-               ver = (header[1] >> 3) & 3;
-               if (ver == 1)
-                       return 0;
-               if (ver == 0)
-                       ver = 2;
-               else if (ver == 2)
-                       ver = 1;
-               else if (ver == 3)
-                       ver = 0;
-               layer = 4 - ((header[1] >> 1) & 3);
-               if (layer == 4)
-                       return 0;
-               iscrc = ((header[1] >> 0) & 1) ? 0 : 2;
-               bitrateidx = (header[2] >> 4) & 15;
-               freq = mp3_frequencies[(header[2] >> 2) & 3];
-               if (!freq)
-                       return 0;
-               channelmode = (header[3] >> 6) & 3;
-               isstereo = channelmode != 3;
-               if (ver == 0) {
-                       bitindex = layer - 1;
-               } else {
-                       if (layer == 1)
-                               bitindex = 3;
-                       else
-                               bitindex = 4;
-               }
-               bitrate = mp3_bitrates[bitindex * 16 + bitrateidx] * 1000;
-               if (bitrate <= 0)
-                       return 0;
-               padding = (header[2] >> 1) & 1;
-               samplerate = mp3_samplesperframe[(layer - 1) * 3 + ver];
-               framelen = ((samplerate / 8 * bitrate) / freq) + padding;
-               if (framelen <= 4)
-                       return 0;
-               zfile_fseek (zf, framelen + iscrc - 4, SEEK_CUR);
-               frames++;
-               size += samplerate * 2 * (isstereo ? 2 : 1);
-       }
-       return size;
-}
-
 #ifdef _WIN32
 
-#include <windows.h>
-#include <mmreg.h>
-#include <msacm.h>
-
-#define MP3_BLOCK_SIZE 522
-
-static HACMSTREAM g_mp3stream = NULL;
-
-static void mp3decoder_close (void)
-{
-       if (g_mp3stream)
-               acmStreamClose (g_mp3stream, 0);
-       g_mp3stream = NULL;
-}
-
-static int mp3decoder_open (void)
-{
-       MMRESULT mmr;
-       LPWAVEFORMATEX waveFormat;
-       LPMPEGLAYER3WAVEFORMAT mp3format;
-       DWORD maxFormatSize;
-
-       if (g_mp3stream)
-               return 1;
-       
-       // find the biggest format size
-       maxFormatSize = 0;
-       mmr = acmMetrics (NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxFormatSize);
-  
-       // define desired output format
-       waveFormat = (LPWAVEFORMATEX) LocalAlloc( LPTR, maxFormatSize );
-       waveFormat->wFormatTag = WAVE_FORMAT_PCM;
-       waveFormat->nChannels = 2; // stereo
-       waveFormat->nSamplesPerSec = 44100; // 44.1kHz
-       waveFormat->wBitsPerSample = 16; // 16 bits
-       waveFormat->nBlockAlign = 4; // 4 bytes of data at a time are useful (1 sample)
-       waveFormat->nAvgBytesPerSec = 4 * 44100; // byte-rate
-       waveFormat->cbSize = 0; // no more data to follow
-  
-       // define MP3 input format
-       mp3format = (LPMPEGLAYER3WAVEFORMAT) LocalAlloc( LPTR, maxFormatSize );
-       mp3format->wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
-       mp3format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
-       mp3format->wfx.nChannels = 2;
-       mp3format->wfx.nAvgBytesPerSec = 128 * (1024 / 8);  // not really used but must be one of 64, 96, 112, 128, 160kbps
-       mp3format->wfx.wBitsPerSample = 0;                  // MUST BE ZERO
-       mp3format->wfx.nBlockAlign = 1;                     // MUST BE ONE
-       mp3format->wfx.nSamplesPerSec = 44100;              // 44.1kHz
-       mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF;
-       mp3format->nBlockSize = MP3_BLOCK_SIZE;             // voodoo value #1
-       mp3format->nFramesPerBlock = 1;                     // MUST BE ONE
-       mp3format->nCodecDelay = 1393;                      // voodoo value #2
-       mp3format->wID = MPEGLAYER3_ID_MPEG;
-  
-       mmr = acmStreamOpen( &g_mp3stream,               // open an ACM conversion stream
-                    NULL,                       // querying all ACM drivers
-                    (LPWAVEFORMATEX) mp3format, // converting from MP3
-                    waveFormat,                 // to WAV
-                    NULL,                       // with no filter
-                    0,                          // or async callbacks
-                    0,                          // (and no data for the callback)
-                    0                           // and no flags
-                    );
-  
-       LocalFree (mp3format);
-       LocalFree (waveFormat);
-       if (mmr == MMSYSERR_NOERROR)
-               return 1;
-       write_log (L"CUEMP3: couldn't open ACM mp3 decoder, %d\n", mmr);
-       return 0;
-}
-
-static uae_u8 *mp3decoder_get (struct zfile *zf, int maxsize)
-{
-       MMRESULT mmr;
-       unsigned long rawbufsize = 0;
-       LPBYTE mp3buf;
-       LPBYTE rawbuf;
-       uae_u8 *outbuf = NULL;
-       int outoffset = 0;
-       ACMSTREAMHEADER mp3streamHead;
-
-       write_log (L"CUEMP3: decoding '%s'..\n", zfile_getname (zf));
-       mmr = acmStreamSize (g_mp3stream, MP3_BLOCK_SIZE, &rawbufsize, ACM_STREAMSIZEF_SOURCE);
-       if (mmr != MMSYSERR_NOERROR) {
-               write_log (L"CUEMP3: acmStreamSize, %d\n", mmr);
-               return NULL;
-       }
-       // allocate our I/O buffers
-       mp3buf = (LPBYTE) LocalAlloc (LPTR, MP3_BLOCK_SIZE);
-       rawbuf = (LPBYTE) LocalAlloc (LPTR, rawbufsize);
-  
-       // prepare the decoder
-       ZeroMemory (&mp3streamHead, sizeof (ACMSTREAMHEADER));
-       mp3streamHead.cbStruct = sizeof (ACMSTREAMHEADER);
-       mp3streamHead.pbSrc = mp3buf;
-       mp3streamHead.cbSrcLength = MP3_BLOCK_SIZE;
-       mp3streamHead.pbDst = rawbuf;
-       mp3streamHead.cbDstLength = rawbufsize;
-       mmr = acmStreamPrepareHeader (g_mp3stream, &mp3streamHead, 0);
-       if (mmr != MMSYSERR_NOERROR) {
-               write_log (L"CUEMP3: acmStreamPrepareHeader, %d\n", mmr);
-               return NULL;
-       }
-       zfile_fseek (zf, 0, SEEK_SET);
-       outbuf = xcalloc (uae_u8, maxsize);
-       for (;;) {
-               int count = zfile_fread (mp3buf, 1, MP3_BLOCK_SIZE, zf);
-               if (count != MP3_BLOCK_SIZE)
-                       break;
-               // convert the data
-               mmr = acmStreamConvert (g_mp3stream, &mp3streamHead, ACM_STREAMCONVERTF_BLOCKALIGN);
-               if (mmr != MMSYSERR_NOERROR) {
-                       write_log (L"CUEMP3: acmStreamConvert, %d\n", mmr);
-                       return NULL;
-               }
-               if (outoffset + mp3streamHead.cbDstLengthUsed > maxsize)
-                       break;
-               memcpy (outbuf + outoffset, rawbuf, mp3streamHead.cbDstLengthUsed);
-               outoffset += mp3streamHead.cbDstLengthUsed;
-       }
-       acmStreamUnprepareHeader (g_mp3stream, &mp3streamHead, 0);
-       LocalFree (rawbuf);
-       LocalFree (mp3buf);
-       write_log (L"CUEMP3: unpacked size %d bytes\n", outoffset);
-       return outbuf;
-}
-
 static HWAVEOUT cdda_wavehandle;
 
 static void cdda_closewav (void)
@@ -320,8 +112,6 @@ static void cdda_closewav (void)
        cdda_wavehandle = NULL;
 }
 
-// DAE CDDA based on Larry Osterman's "Playing Audio CDs" blog series
-
 static int cdda_openwav (void)
 {
        WAVEFORMATEX wav = { 0 };
@@ -343,6 +133,90 @@ static int cdda_openwav (void)
        return 1;
 }
 
+static int getsub (uae_u8 *dst, struct cdunit *cdu, struct cdtoc *t, int sector)
+{
+       int ret = 0;
+       uae_sem_wait (&cdu->sub_sem);
+       if (t->subcode) {
+               if (t->subhandle) {
+                       zfile_fseek (t->subhandle, sector * SUB_CHANNEL_SIZE + t->suboffset, SEEK_SET);
+                       if (zfile_fread (dst, SUB_CHANNEL_SIZE, 1, t->subhandle) > 0)
+                               ret = t->subcode;
+               } else {
+                       memcpy (dst, t->subdata + sector * SUB_CHANNEL_SIZE + t->suboffset, SUB_CHANNEL_SIZE);
+                       ret = t->subcode;
+               }
+       }
+       if (!ret) {
+               memset (dst, 0, SUB_CHANNEL_SIZE);
+               // regenerate Q-subchannel
+               uae_u8 *s = dst + 12;
+               s[0] = (t->ctrl << 4) | (t->adr << 0);
+               s[1] = tobcd (t - &cdu->toc[0] + 1);
+               s[2] = tobcd (1);
+               int msf = lsn2msf (sector);
+               tolongbcd (s + 7, msf);
+               msf = lsn2msf (sector - t->address - 150);
+               tolongbcd (s + 3, msf);
+               ret = 2;
+       }
+       uae_sem_post (&cdu->sub_sem);
+       return ret;
+}
+
+static void dosub (struct cdunit *cdu, struct cdtoc *t, int sector)
+{
+       uae_u8 *s, *d;
+       uae_u8 subbuf[SUB_CHANNEL_SIZE];
+       uae_u8 subbuf2[SUB_CHANNEL_SIZE];
+
+       if (!cdu->cdda_subfunc)
+               return;
+
+       if (!t) {
+               memset (subbuf, 0, sizeof subbuf);
+               cdu->cdda_subfunc (subbuf, 1);
+               return;
+       }
+       memset (subbuf, 0, SUB_CHANNEL_SIZE);
+       int mode = getsub (subbuf, cdu, t, sector);
+       if (mode == 2) { // deinterleaved -> interleaved
+               s = subbuf;
+               d = subbuf2;
+               for (int i = 0; i < 8 * 12; i ++) {
+                       int dmask = 0x80;
+                       int smask = 1 << (7 - (i & 7));
+                       (*d) = 0;
+                       for (int j = 0; j < 8; j++) {
+                               (*d) |= (s[(i / 8) + j * 12] & smask) ? dmask : 0;
+                               dmask >>= 1;
+                       }
+                       d++;
+               }
+#if 0
+               uae_u8 subbuf3[SUB_CHANNEL_SIZE];
+               s = subbuf2;
+               d = subbuf3;
+               for (int i = 0; i < 8 * 12; i ++) {
+                       int dmask = 0x80;
+                       int smask = 1 << (7 - (i / 12));
+                       (*d) = 0;
+                       for (int j = 0; j < 8; j++) {
+                               (*d) |= (s[(i % 12) * 8 + j] & smask) ? dmask : 0;
+                               dmask >>= 1;
+                       }
+                       d++;
+               }
+#endif
+               d = subbuf2;
+
+
+       } else {
+               d = subbuf;
+       }
+       cdu->cdda_subfunc (d, 1);
+}
+
 static void *cdda_play_func (void *v)
 {
        int cdda_pos;
@@ -357,13 +231,16 @@ static void *cdda_play_func (void *v)
        MMRESULT mmr;
        int volume, volume_main;
        int oldplay;
+       mp3decoder *mp3dec = NULL;
+       struct cdunit *cdu = &cdunits[0];
+       int firstloops;
 
        for (i = 0; i < 2; i++) {
                memset (&whdr[i], 0, sizeof (WAVEHDR));
                whdr[i].dwFlags = WHDR_DONE;
        }
 
-       while (cdda_play == 0)
+       while (cdu->cdda_play == 0)
                Sleep (10);
        oldplay = -1;
 
@@ -390,68 +267,84 @@ static void *cdda_play_func (void *v)
                        whdr[i].dwFlags |= WHDR_DONE;
                }
 
-               while (cdda_play > 0) {
+               while (cdu->cdda_play > 0) {
 
-                       if (oldplay != cdda_play) {
+                       if (oldplay != cdu->cdda_play) {
                                struct cdtoc *t;
                                int sector;
 
-                               cdda_pos = cdda_start;
-                               oldplay = cdda_play;
-
-                               sector = cdda_start;
-                               t = findtoc (&sector);
+                               cdda_pos = cdu->cdda_start;
+                               oldplay = cdu->cdda_play;
+                               cdu->cd_last_pos = cdda_pos;
+                               sector = cdu->cdda_start;
+                               t = findtoc (cdu, &sector);
                                if (!t) {
-                                       write_log (L"CDDA: illegal sector number %d\n", cdda_start);
+                                       write_log (L"CDDA: illegal sector number %d\n", cdu->cdda_start);
                                } else {
-                                       write_log (L"CDDA: playing track %d (file '%s', offset %d, secoffset %d)\n",
-                                               t->track, t->fname, t->offset, sector);
+                                       write_log (L"CDDA: playing from %d to %d, track %d ('%s', offset %d, secoffset %d)\n",
+                                               cdu->cdda_start, cdu->cdda_end, t->track, t->fname, t->offset, sector);
                                        if (t->mp3 && !t->data) {
-                                               if (mp3decoder_open ()) {
-                                                       t->data = mp3decoder_get (t->handle, t->filesize);
+                                               if (!mp3dec) {
+                                                       try {
+                                                               mp3dec = new mp3decoder();
+                                                       } catch (exception) { };
                                                }
+                                               if (mp3dec)
+                                                       t->data = mp3dec->get (t->handle, t->filesize);
                                        }
                                }
+                               firstloops = 25;
                        }
 
                        while (!(whdr[bufnum].dwFlags & WHDR_DONE)) {
                                Sleep (10);
-                               if (!cdda_play)
+                               if (!cdu->cdda_play)
                                        goto end;
                        }
                        bufon[bufnum] = 0;
 
-                       if ((cdda_pos < cdda_end || cdda_end == 0xffffffff) && !cdda_paused && cdda_play > 0) {
+                       if ((cdda_pos < cdu->cdda_end || cdu->cdda_end == 0xffffffff) && !cdu->cdda_paused && cdu->cdda_play > 0) {
                                struct cdtoc *t;
                                int sector, cnt;
                                int dofinish = 0;
 
                                memset (px[bufnum], 0, num_sectors * 2352);
-                               for (cnt = 0; cnt < num_sectors; cnt++) {
-                                       sector = cdda_pos;
-
-                                       cdda_pos++;
-                                       if (cdda_pos - num_sectors < cdda_end && cdda_pos >= cdda_end)
-                                               dofinish = 1;
-                                       cd_last_pos = cdda_pos;
-
-                                       t = findtoc (&sector);
-                                       if (t) {
-                                               if (t->handle && !(t->ctrl & 4)) {
-                                                       uae_u8 *dst = px[bufnum] + cnt * t->size;
-                                                       if (t->mp3 && t->data) {
-                                                               memcpy (dst, t->data + sector * t->size + t->offset, t->size);
-                                                       } else if (!t->mp3) {
-                                                               if (sector * t->size + t->offset + t->size < t->filesize) {
-                                                                       zfile_fseek (t->handle, sector * t->size + t->offset, SEEK_SET);
-                                                                       zfile_fread (dst, t->size, 1, t->handle);
+
+                               if (firstloops > 0) {
+
+                                       firstloops--;
+                                       for (cnt = 0; cnt < num_sectors; cnt++)
+                                               dosub (cdu, NULL, -1);
+                                       
+                               } else {
+
+                                       for (cnt = 0; cnt < num_sectors; cnt++) {
+                                               sector = cdda_pos;
+
+                                               cdda_pos++;
+                                               if (cdda_pos - num_sectors < cdu->cdda_end && cdda_pos >= cdu->cdda_end)
+                                                       dofinish = 1;
+
+                                               t = findtoc (cdu, &sector);
+                                               if (t) {
+                                                       if (t->handle && !(t->ctrl & 4)) {
+                                                               uae_u8 *dst = px[bufnum] + cnt * t->size;
+                                                               if (t->mp3 && t->data) {
+                                                                       memcpy (dst, t->data + sector * t->size + t->offset, t->size);
+                                                               } else if (!t->mp3) {
+                                                                       if (sector * t->size + t->offset + t->size < t->filesize) {
+                                                                               zfile_fseek (t->handle, sector * t->size + t->offset, SEEK_SET);
+                                                                               zfile_fread (dst, t->size, 1, t->handle);
+                                                                       }
                                                                }
                                                        }
+                                                       dosub (cdu, t, cdda_pos);
                                                }
                                        }
+
                                }
        
-                               volume = cdda_volume;
+                               volume = cdu->cdda_volume;
                                volume_main = currprefs.sound_volume;
                                int vol_mult = (100 - volume_main) * volume / 100;
                                if (vol_mult)
@@ -472,10 +365,12 @@ static void *cdda_play_func (void *v)
                                        break;
                                }
 
+                               cdu->cd_last_pos = cdda_pos;
+
                                if (dofinish) {
-                                       cdda_play_finished = 1;
-                                       cdda_play = -1;
-                                       cdda_pos = cdda_end + 1;
+                                       cdu->cdda_play_finished = 1;
+                                       cdu->cdda_play = -1;
+                                       cdda_pos = cdu->cdda_end + 1;
                                }
 
                        }
@@ -484,7 +379,7 @@ static void *cdda_play_func (void *v)
                        if (bufon[0] == 0 && bufon[1] == 0) {
                                while (!(whdr[0].dwFlags & WHDR_DONE) || !(whdr[1].dwFlags & WHDR_DONE))
                                        Sleep (10);
-                               while (cdda_paused && cdda_play > 0)
+                               while (cdu->cdda_paused && cdu->cdda_play > 0)
                                        Sleep (10);
                        }
 
@@ -501,124 +396,126 @@ end:
 
        cdda_closewav ();
        xfree (p);
-       cdda_play = 0;
+       delete mp3dec;
+       cdu->cdda_play = 0;
        write_log (L"CDDA: thread killed\n");
        return NULL;
 }
 
 #endif
 
-static void cdda_stop (void)
+static void cdda_stop (struct cdunit *cdu)
 {
-       if (cdda_play > 0) {
-               cdda_play = -1;
-               while (cdda_play) {
+       if (cdu->cdda_play > 0) {
+               cdu->cdda_play = -1;
+               while (cdu->cdda_play) {
                        Sleep (10);
                }
        }
-       cdda_play_finished = 0;
-       cdda_paused = 0;
+       cdu->cdda_play_finished = 0;
+       cdu->cdda_paused = 0;
 }
 
 
 static int command_pause (int unitnum, int paused)
 {
+       struct cdunit *cdu = &cdunits[unitnum];
        if (unitnum)
                return 0;
-       cdda_paused = paused;
+       cdu->cdda_paused = paused;
        return 1;
 }
 
 static int command_stop (int unitnum)
 {
+       struct cdunit *cdu = &cdunits[unitnum];
        if (unitnum)
                return 0;
-       cdda_stop ();
+       cdda_stop (cdu);
        return 1;
 }
 
-static int command_play (int unitnum, uae_u32 start, uae_u32 end, int scan)
+static int command_play (int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc)
 {
+       struct cdunit *cdu = &cdunits[unitnum];
        if (unitnum)
                return 0;
 
-       cdda_paused = 0;
-       cdda_play_finished = 0;
-       cdda_start = msf2lsn (start);
-       cdda_end = msf2lsn (end);
-       if (!cdda_play)
+       cdu->cdda_paused = 0;
+       cdu->cdda_play_finished = 0;
+       cdu->cd_last_pos = startlsn;
+       cdu->cdda_start = startlsn;
+       cdu->cdda_end = endlsn;
+       cdu->cdda_subfunc = subfunc;
+       if (!cdu->cdda_play)
                uae_start_thread (L"cdda_play", cdda_play_func, NULL, NULL);
-       cdda_play++;
+       cdu->cdda_play++;
        return 1;
 }
 
-static uae_u8 *command_qcode (int unitnum)
+static int command_qcode (int unitnum, uae_u8 *buf, int sector)
 {
-       static uae_u8 buf[4 + 12];
+       struct cdunit *cdu = &cdunits[unitnum];
+       uae_u8 subbuf[SUB_CHANNEL_SIZE];
        uae_u8 *p;
        int trk;
        int pos;
-       int msf;
-       int start, end;
        int status;
 
        if (unitnum)
                return NULL;
 
-       memset (buf, 0, sizeof buf);
+       memset (buf, 0, SUBQ_SIZE);
        p = buf;
 
        status = AUDIO_STATUS_NO_STATUS;
-       if (cdda_play > 0) {
+       if (cdu->cdda_play > 0) {
                status = AUDIO_STATUS_IN_PROGRESS;
-               if (cdda_paused)
+               if (cdu->cdda_paused)
                        status = AUDIO_STATUS_PAUSED;
-       } else if (cdda_play_finished) {
+       } else if (cdu->cdda_play_finished) {
                status = AUDIO_STATUS_PLAY_COMPLETE;
        }
-       pos = cd_last_pos;
+       if (sector < 0)
+               pos = cdu->cd_last_pos;
+       else
+               pos = sector;
 
        p[1] = status;
        p[3] = 12;
 
        p = buf + 4;
 
-       start = end = 0;
-       for (trk = 0; trk <= tracks; trk++) {
-               struct cdtoc *td = &toc[trk];
-               if (pos < td->address)
-                       break;
-               if (pos >= td->address && pos < td[1].address) {
-                       start = td->address;
+       struct cdtoc *td = NULL;
+       for (trk = 0; trk <= cdu->tracks; trk++) {
+               td = &cdu->toc[trk];
+               if (pos < td->address) {
+                       if (trk > 0)
+                               td--;
                        break;
                }
+               if (pos >= td->address && pos < td[1].address)
+                       break;
        }
-       p[1] = (toc[trk].ctrl << 0) | (toc[trk].adr << 4);
-       p[2] = trk + 1;
-       p[3] = 1;
-       msf = lsn2msf (pos);
-       p[5] = (msf >> 16) & 0xff;
-       p[6] = (msf >> 8) & 0xff;
-       p[7] = (msf >> 0) & 0xff;
-       pos -= start;
-       if (pos < 0)
-               pos = 0;
-       msf = lsn2msf (pos - 150);
-       p[9] = (msf >> 16) & 0xff;
-       p[10] = (msf >> 8) & 0xff;
-       p[11] = (msf >> 0) & 0xff;
-
-       return buf;
+       if (!td)
+               return 0;
+       getsub (subbuf, cdu, td, pos);
+       memcpy (p, subbuf + 12, 12);
+//     write_log (L"%6d %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n",
+//             pos, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]);
+       return 1;
 }
 
 static void command_volume (int unitnum, uae_u16 volume)
 {
-       cdda_volume = volume;
+       struct cdunit *cdu = &cdunits[unitnum];
+       cdu->cdda_volume = volume;
 }
 
-uae_u8 *command_rawread (int unitnum, int sector, int sectorsize)
+uae_u8 *command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize)
 {
-       struct cdtoc *t = findtoc (&sector);
+       struct cdunit *cdu = &cdunits[unitnum];
+       struct cdtoc *t = findtoc (cdu, &sector);
        int offset;
 
        if (unitnum)
@@ -626,87 +523,92 @@ uae_u8 *command_rawread (int unitnum, int sector, int sectorsize)
        if (!t || t->handle == NULL)
                return NULL;
 
-       cdda_stop ();
+       cdda_stop (cdu);
        if (sectorsize > t->size)
                return NULL;
        offset = 0;
        if (sectorsize == 2336 && t->size == 2352)
                offset = 16;
        zfile_fseek (t->handle, t->offset + sector * t->size + offset, SEEK_SET);
-       zfile_fread (buffer, sectorsize, 1, t->handle);
-       return buffer;
+       if (data)
+               zfile_fread (data, sectorsize, size, t->handle);
+       else
+               zfile_fread (cdu->buffer, sectorsize, 1, t->handle);
+       cdu->cd_last_pos = sector;
+       return cdu->buffer;
 }
 
-static uae_u8 *command_read (int unitnum, int sector)
+static uae_u8 *command_read (int unitnum, uae_u8 *data, int sector, int size)
 {
-       struct cdtoc *t = findtoc (&sector);
+       struct cdunit *cdu = &cdunits[unitnum];
+       struct cdtoc *t = findtoc (cdu, &sector);
        int offset;
 
        if (unitnum)
                return NULL;
        if (!t || t->handle == NULL)
                return NULL;
-       cdda_stop ();
+       cdda_stop (cdu);
        offset = 0;
        if (t->size > 2048)
                offset = 16;
        zfile_fseek (t->handle, t->offset + sector * t->size + offset, SEEK_SET);
-       zfile_fread (buffer, 2048, 1, t->handle);
-       return buffer;
+       if (data)
+               zfile_fread (data, size, 2048, t->handle);
+       else
+               zfile_fread (cdu->buffer, 2048, 1, t->handle);
+       cdu->cd_last_pos = sector;
+       return cdu->buffer;
 }
 
-static uae_u8 *command_toc (int unitnum)
+static struct cd_toc_head *command_toc (int unitnum)
 {
-       static uae_u8 statictoc[11 * 102];
-       uae_u8 *p = statictoc;
+       struct cdunit *cdu = &cdunits[unitnum];
+       static struct cd_toc_head statictoc;
+       struct cd_toc *toc = &statictoc.toc[0];
        int i;
-       uae_u32 msf;
 
        if (unitnum)
                return NULL;
-       cdda_stop ();
-       if (!tracks)
+       cdda_stop (cdu);
+       if (!cdu->tracks)
                return NULL;
-       p[0] = ((tracks + 4) * 11) >> 8;
-       p[1] = ((tracks + 4) * 11) & 0xff;
-       p[2] = 1;
-       p[3] = tracks;
-       p += 4;
-       memset (p, 0, 11);
-       p[0] = 1;
-       p[1] = (toc[0].ctrl << 0) | (toc[0].adr << 4);
-       p[3] = 0xa0;
-       p[8] = 1;
-       p += 11;
-       memset (p, 0, 11);
-       p[0] = 1;
-       p[1] = 0x10;
-       p[3] = 0xa1;
-       p[8] = tracks;
-       p += 11;
-       memset (p, 0, 11);
-       p[0] = 1;
-       p[1] = 0x10;
-       p[3] = 0xa2;
-       msf = lsn2msf (toc[tracks].address);
-       p[8] = msf >> 16;
-       p[9] = msf >> 8;
-       p[10] = msf >> 0;
-       p += 11;
-       for (i = 0; i < tracks; i++) {
-               memset (p, 0, 11);
-               p[0] = 1;
-               p[1] = (toc[i].ctrl << 0) | (toc[i].adr << 4);
-               p[2] = 0;
-               p[3] = i + 1;
-               msf = lsn2msf (toc[i].address);
-               p[8] = msf >> 16;
-               p[9] = msf >> 8;
-               p[10] = msf >> 0;
-               p += 11;
+
+       memset (&statictoc, 0, sizeof statictoc);
+       statictoc.first_track = 1;
+       statictoc.last_track = cdu->tracks;
+       statictoc.points = cdu->tracks + 3;
+       statictoc.tracks = cdu->tracks;
+       statictoc.lastaddress = cdu->toc[cdu->tracks].address;
+
+       toc->adr = 1;
+       toc->point = 0xa0;
+       toc->track = statictoc.first_track;
+       toc++;
+
+       statictoc.first_track_offset = 1;
+       for (i = 0; i < cdu->tracks; i++) {
+               toc->adr = cdu->toc[i].adr;
+               toc->control = cdu->toc[i].ctrl;
+               toc->track = i + 1;
+               toc->point = i + 1;
+               toc->paddress = cdu->toc[i].address;
+               toc++;
        }
+
+       statictoc.last_track_offset = cdu->tracks;
+       toc->adr = 1;
+       toc->point = 0xa1;
+       toc->track = statictoc.last_track;
+       toc++;
+
+       toc->adr = 1;
+       toc->point = 0xa2;
+       toc->paddress = statictoc.lastaddress;
+       toc++;
+
        gui_flicker_led (LED_CD, unitnum, 1);
-       return statictoc;
+       return &statictoc;
 }
 
 static void skipspace (TCHAR **s)
@@ -742,26 +644,152 @@ static TCHAR *nextstring (TCHAR **sp)
        return out;
 }
 
-static int parse_image (void)
+static int readval (const TCHAR *s)
+{
+       int base = 10;
+       TCHAR *endptr;
+       if (s[0] == '0' && _totupper (s[1]) == 'X')
+               s += 2, base = 16;
+       return _tcstol (s, &endptr, base);
+}
+
+static int parseccd (struct cdunit *cdu, struct zfile *zcue, TCHAR *img)
+{
+       int mode;
+       int num, tracknum, trackmode;
+       int adr, control, lba;
+       bool gotlba;
+       struct cdtoc *t;
+       struct zfile *zimg, *zsub;
+       TCHAR fname[MAX_DPATH];
+       
+       write_log (L"CCD TOC: '%s'\n", img);
+       _tcscpy (fname, img);
+       TCHAR *ext = _tcsrchr (fname, '.');
+       if (ext)
+               *ext = 0;
+       _tcscat (fname, L".img");
+       zimg = zfile_fopen (fname, L"rb", ZFD_NORMAL);
+       if (!zimg) {
+               write_log (L"CCD: can't open '%s'\n", fname);
+               //return 0;
+       }
+       ext = _tcsrchr (fname, '.');
+       if (ext)
+               *ext = 0;
+       _tcscat (fname, L".sub");
+       zsub = zfile_fopen (fname, L"rb", ZFD_NORMAL);
+       if (zsub)
+               write_log (L"CCD: '%s' detected\n", fname);
+
+       num = -1;
+       mode = -1;
+       for (;;) {
+               TCHAR buf[MAX_DPATH], *p;
+               if (!zfile_fgets (buf, sizeof buf / sizeof (TCHAR), zcue))
+                       break;
+               p = buf;
+               skipspace (&p);
+               if (!_tcsnicmp (p, L"[DISC]", 6)) {
+                       mode = 1;
+               } else if (!_tcsnicmp (p, L"[ENTRY ", 7)) {
+                       t = NULL;
+                       mode = 2;
+                       num = readval (p + 7);
+                       if (num < 0)
+                               break;
+                       adr = control = -1;
+                       gotlba = false;
+               } else if (!_tcsnicmp (p, L"[TRACK ", 7)) {
+                       mode = 3;
+                       tracknum = readval (p + 7);
+                       trackmode = -1;
+                       if (tracknum <= 0 || tracknum > 99)
+                               break;
+                       t = &cdu->toc[tracknum - 1];
+               }
+               if (mode < 0)
+                       continue;
+               if (mode == 1) {
+                       if (!_tcsnicmp (p, L"TocEntries=", 11)) {
+                               cdu->tracks = readval (p + 11) - 3;
+                               if (cdu->tracks <= 0 || cdu->tracks > 99)
+                                       break;
+                       }
+                       continue;
+               }
+               if (cdu->tracks <= 0)
+                       break;
+               
+               if (mode == 2) {
+
+                       if (!_tcsnicmp (p, L"SESSION=", 8)) {
+                               if (readval (p + 8) != 1)
+                                       mode = -1;
+                               continue;
+                       } else if (!_tcsnicmp (p, L"POINT=", 6)) {
+                               tracknum = readval (p + 6);
+                               if (tracknum <= 0)
+                                       break;
+                               if (tracknum >= 0xa0 && tracknum != 0xa2) {
+                                       mode = -1;
+                                       continue;
+                               }
+                               if (tracknum == 0xa2)
+                                       tracknum = cdu->tracks + 1;
+                               t = &cdu->toc[tracknum - 1];
+                               continue;
+                       }
+                       if (!_tcsnicmp (p, L"ADR=", 4))
+                               adr = readval (p + 4);
+                       if (!_tcsnicmp (p, L"CONTROL=", 8))
+                               control = readval (p + 8);
+                       if (!_tcsnicmp (p, L"PLBA=", 5)) {
+                               lba = readval (p + 5);
+                               gotlba = true;
+                       }
+                       if (gotlba && adr >= 0 && control >= 0) {
+                               t->adr = adr;
+                               t->ctrl = control;
+                               t->address = lba;
+                               t->offset = 0;
+                               t->size = 2352;
+                               t->offset = lba * t->size;
+                               t->track = tracknum;
+                               if (zsub) {
+                                       t->subcode = 2;
+                                       t->subhandle = zfile_dup (zsub);
+                                       t->suboffset = 0;
+                               }
+                               if (zimg) {
+                                       t->handle = zfile_dup (zimg);
+                                       t->fname = my_strdup (zfile_getname (zimg));
+                                       t->filesize = zfile_size (t->handle);
+                               }
+                               mode = -1;
+                       }
+
+               } else if (mode == 3) {
+
+                       if (!_tcsnicmp (p, L"MODE=", 5))
+                               trackmode = _tstol (p + 5);
+                       if (trackmode < 0 || trackmode > 2)
+                               continue;
+                       
+               }
+
+       }
+       return cdu->tracks;
+}
+
+static int parsecue (struct cdunit *cdu, struct zfile *zcue, TCHAR *img)
 {
-       struct zfile *zcue;
-       TCHAR *fname, *fnametype;
        int tracknum, index0, pregap;
        int offset, secoffset, newfile;
-       int i;
-       TCHAR *p;
-       TCHAR curdir[MAX_DPATH], oldcurdir[MAX_DPATH];
-       uae_u64 siz;
-       TCHAR *img = currprefs.cdimagefile;
+       TCHAR *fname, *fnametype;
        int ctrl;
+       mp3decoder *mp3dec = NULL;
 
-       if (!img)
-               return 0;
-       zcue = zfile_fopen (img, L"rb", ZFD_ARCHIVE | ZFD_CD);
-       if (!zcue)
-               return 0;
-
-       oldcurdir[0] = 0;
        fname = NULL;
        fnametype = NULL;
        tracknum = 0;
@@ -772,39 +800,9 @@ static int parse_image (void)
        index0 = -1;
        pregap = 0;
 
-       siz = zfile_size (zcue);
-       if (siz >= 16384) {
-               if ((siz % 2048) == 0 || (siz % 2352) == 0) {
-                       struct cdtoc *t = &toc[0];
-                       tracks = 1;
-                       t->ctrl = 4;
-                       t->adr = 1;
-                       t->fname = my_strdup (img);
-                       t->handle = zcue;
-                       t->size = (siz % 2048) == 0 ? 2048 : 2352;
-                       t->filesize = siz;
-                       write_log (L"CUE: plain CD image mounted!\n");
-                       zcue = NULL;
-                       goto isodone;
-               }
-               zfile_fclose (zcue);
-               return 0;
-       }
-
        write_log (L"CUE TOC: '%s'\n", img);
-       _tcscpy (curdir, img);
-       oldcurdir[0] = 0;
-       p = curdir + _tcslen (curdir);
-       while (p > curdir) {
-               if (*p == '/' || *p == '\\')
-                       break;
-               p--;
-       }
-       *p = 0;
-       if (p > curdir)
-               my_setcurrentdir (curdir, oldcurdir);
        for (;;) {
-               TCHAR buf[MAX_DPATH];
+               TCHAR buf[MAX_DPATH], *p;
                if (!zfile_fgets (buf, sizeof buf / sizeof (TCHAR), zcue))
                        break;
 
@@ -816,6 +814,8 @@ static int parse_image (void)
                        xfree (fname);
                        fname = my_strdup (nextstring (&p));
                        fnametype = nextstring (&p);
+                       if (!fnametype)
+                               break;
                        if (_tcsicmp (fnametype, L"BINARY") && _tcsicmp (fnametype, L"WAVE") && _tcsicmp (fnametype, L"MP3")) {
                                write_log (L"CUE: unknown file type '%s' ('%s')\n", fnametype, fname);
                        }
@@ -844,6 +844,8 @@ static int parse_image (void)
                        index0 = -1;
                        tracknum = _tstoi (nextstring (&p));
                        tracktype = nextstring (&p);
+                       if (!tracktype)
+                               break;
                        size = 2352;
                        if (!_tcsicmp (tracktype, L"AUDIO")) {
                                ctrl &= ~4;
@@ -862,7 +864,7 @@ static int parse_image (void)
                                }
                        }
                        if (tracknum >= 1 && tracknum <= 99) {
-                               struct cdtoc *t = &toc[tracknum - 1];
+                               struct cdtoc *t = &cdu->toc[tracknum - 1];
                                struct zfile *ztrack;
 
                                if (tracknum > 1 && newfile) {
@@ -909,8 +911,8 @@ static int parse_image (void)
                                t->handle = ztrack;
                                t->size = size;
                                t->fname = my_strdup (fname);
-                               if (tracknum > tracks)
-                                       tracks = tracknum;
+                               if (tracknum > cdu->tracks)
+                                       cdu->tracks = tracknum;
                                if (t->handle)
                                        t->filesize = zfile_size (t->handle);
                        }
@@ -936,7 +938,7 @@ static int parse_image (void)
                        if (idxnum == 0) {
                                index0 = tn;
                        } else if (idxnum == 1 && tracknum >= 1 && tracknum <= 99) {
-                               struct cdtoc *t = &toc[tracknum - 1];
+                               struct cdtoc *t = &cdu->toc[tracknum - 1];
                                if (!t->address) {
                                        t->address = tn + secoffset;
                                        t->address += pregap;
@@ -968,109 +970,189 @@ static int parse_image (void)
                                                        t->filesize = size;
                                                }
                                        } else if (!_tcsicmp (fnametype, L"MP3") && t->handle) {
-                                               t->offset = 0;
-                                               t->filesize = mp3decoder_getsize (t->handle);
-                                               if (t->filesize)
-                                                       t->mp3 = 1;
+                                               if (!mp3dec) {
+                                                       try {
+                                                               mp3dec = new mp3decoder();
+                                                       } catch (exception) { }
+                                               }
+                                               if (mp3dec) {
+                                                       t->offset = 0;
+                                                       t->filesize = mp3dec->getsize (t->handle);
+                                                       if (t->filesize)
+                                                               t->mp3 = 1;
+                                               }
                                        }
                                }
                        }
                }
        }
-isodone:
-       if (tracks && toc[tracks - 1].handle) {
-               struct cdtoc *t = &toc[tracks - 1];
-               int size = t->filesize;
-               if (!secoffset)
-                       size -= offset * t->size;
-               if (size < 0)
-                       size = 0;
-               toc[tracks].address = t->address + size / t->size;
-               cdsize = toc[tracks].address * t->size;
-       }
+
+       struct cdtoc *t = &cdu->toc[cdu->tracks - 1];
+       int size = t->filesize;
+       if (!secoffset)
+               size -= offset * t->size;
+       if (size < 0)
+               size = 0;
+       cdu->toc[cdu->tracks].address = t->address + size / t->size;
+
        xfree (fname);
-       if (oldcurdir[0])
-               my_setcurrentdir (oldcurdir, NULL);
-       for (i = 0; i <= tracks; i++) {
-               struct cdtoc *t = &toc[i];
+
+       delete mp3dec;
+
+       return cdu->tracks;
+}
+
+static int parse_image (struct cdunit *cdu)
+{
+       struct zfile *zcue;
+       int i;
+       TCHAR *img = currprefs.cdimagefile;
+       TCHAR *ext;
+       int secoffset;
+
+       secoffset = 0;
+       cdu->tracks = 0;
+       if (!img)
+               return 0;
+       zcue = zfile_fopen (img, L"rb", ZFD_ARCHIVE | ZFD_CD);
+       if (!zcue)
+               return 0;
+
+       ext = _tcsrchr (img, '.');
+       if (ext) {
+               TCHAR curdir[MAX_DPATH];
+               TCHAR oldcurdir[MAX_DPATH], *p;
+
+               ext++;
+               oldcurdir[0] = 0;
+               _tcscpy (curdir, img);
+               p = curdir + _tcslen (curdir);
+               while (p > curdir) {
+                       if (*p == '/' || *p == '\\')
+                               break;
+                       p--;
+               }
+               *p = 0;
+               if (p > curdir)
+                       my_setcurrentdir (curdir, oldcurdir);
+
+               if (!_tcsicmp (ext, L"cue"))
+                       parsecue (cdu, zcue, img);
+               else if (!_tcsicmp (ext, L"ccd"))
+                       parseccd (cdu, zcue, img);
+
+               if (oldcurdir[0])
+                       my_setcurrentdir (oldcurdir, NULL);
+       }
+       if (!cdu->tracks) {
+               uae_u64 siz = zfile_size (zcue);
+               if (siz >= 16384 && (siz % 2048) == 0 || (siz % 2352) == 0) {
+                       struct cdtoc *t = &cdu->toc[0];
+                       cdu->tracks = 1;
+                       t->ctrl = 4;
+                       t->adr = 1;
+                       t->fname = my_strdup (img);
+                       t->handle = zcue;
+                       t->size = (siz % 2048) == 0 ? 2048 : 2352;
+                       t->filesize = siz;
+                       write_log (L"CUE: plain CD image mounted!\n");
+                       cdu->toc[1].address = t->address + t->filesize / t->size;
+                       zcue = NULL;
+               }
+       }
+
+       for (i = 0; i <= cdu->tracks; i++) {
+               struct cdtoc *t = &cdu->toc[i];
                uae_u32 msf = lsn2msf (t->address);
-               if (i < tracks)
+               if (i < cdu->tracks)
                        write_log (L"%2d: ", i + 1);
                else
                        write_log (L"    ");
                write_log (L"%7d %02d:%02d:%02d",
                        t->address, (msf >> 16) & 0xff, (msf >> 8) & 0xff, (msf >> 0) & 0xff);
-               if (i < tracks)
-                       write_log (L" %s %x %10d %s", (t->ctrl & 4) ? L"DATA" : L"CDA ", t->ctrl, t->offset, t->handle == NULL ? L"[FILE ERROR]" : L"");
+               if (i < cdu->tracks)
+                       write_log (L" %s %x %10d %s", (t->ctrl & 4) ? L"DATA    " : (t->subcode ? L"CDA+SUB" : L"CDA     "),
+                               t->ctrl, t->offset, t->handle == NULL ? L"[FILE ERROR]" : L"");
                write_log (L"\n");
-               if (i < tracks)
+               if (i < cdu->tracks)
                        write_log (L" - %s\n", t->fname);
        }
+
+       cdu->blocksize = 2048;
+       cdu->cdsize = cdu->toc[cdu->tracks].address * cdu->blocksize;
+
        zfile_fclose (zcue);
-       mp3decoder_close ();
        return 1;
 }
 
-static void unload_image (void)
+static void unload_image (struct cdunit *cdu)
 {
        int i;
 
-       for (i = 0; i < tracks; i++) {
-               struct cdtoc *t = &toc[i];
+       for (i = 0; i < cdu->tracks; i++) {
+               struct cdtoc *t = &cdu->toc[i];
                zfile_fclose (t->handle);
+               if (t->handle != t->subhandle)
+                       zfile_fclose (t->subhandle);
                xfree (t->fname);
                xfree (t->data);
+               xfree (t->subdata);
        }
-       memset (toc, 0, sizeof toc);
-       tracks = 0;
-       cdsize = 0;
+       memset (cdu->toc, 0, sizeof cdu->toc);
+       cdu->tracks = 0;
+       cdu->cdsize = 0;
 }
 
+
 static int open_device (int unitnum)
 {
-       if (unitnum)
+       struct cdunit *cdu = &cdunits[unitnum];
+       if (!cdu->enabled)
                return 0;
-       if (!tracks)
-               parse_image ();
+       uae_sem_init (&cdu->sub_sem, 0, 1);
+       if (!cdu->tracks)
+               parse_image (cdu);
        return 1;
 }
 
 static void close_device (int unitnum)
 {
-       unload_image ();
+       struct cdunit *cdu = &cdunits[unitnum];
+       unload_image (cdu);
+       uae_sem_destroy (&cdu->sub_sem);
 }
 
-static int mountme (bool checkparse)
+static int mountme (struct cdunit *cdu, bool checkparse)
 {
        sys_command_setunit (-1);
 
        bool sel = false;
-       donotmountme = 1;
-       device_func_init (DEVICE_TYPE_ANY);
+       cdu->donotmountme = 1;
+       device_func_init (DEVICE_TYPE_ANY | DEVICE_TYPE_USE_OLD);
        for (int i = 0; i < MAX_TOTAL_DEVICES && !sel; i++) {
                int opened = sys_command_isopen (i);
                struct device_info *discsi, discsi2;
                discsi = 0;
                if (sys_command_open (DF_IOCTL, i)) {
-                       discsi = sys_command_info (DF_IOCTL, i, &discsi2);
+                       discsi = sys_command_info (DF_IOCTL, i, &discsi2, 0);
                        if (discsi && discsi->type == INQ_ROMD) {
                                if (!_tcsicmp (currprefs.cdimagefile, discsi->label)) {
                                        sys_command_setunit (i);
                                        write_log (L"Drive '%s' (unit=%d) selected (media=%d)\n", discsi->label, i, discsi->media_inserted);
-                                       donotmountme = false;
+                                       cdu->donotmountme = false;
                                        return -1;
                                }
                        }
                }
        }
-       donotmountme = -1;
-       device_func_init (DEVICE_TYPE_ANY); // activate us again
-       donotmountme = 0;
+       cdu->donotmountme = -1;
+       device_func_init (DEVICE_TYPE_ANY | DEVICE_TYPE_USE_OLD); // activate us again
+       cdu->donotmountme = 0;
        if (checkparse) {
                sys_command_setunit (0);
-               parse_image ();
-               int media = tracks > 0;
-               write_log (L"IMG_EMU (%s) selected (media=%d)\n", currprefs.cdimagefile, media);
+               parse_image (cdu);
+               int media = cdu->tracks > 0;
+               write_log (L"CDEMU (%s) selected (media=%d)\n", currprefs.cdimagefile, media);
                return 1;
        }
        return 0;
@@ -1078,39 +1160,44 @@ static int mountme (bool checkparse)
 
 void cdimage_vsync (void)
 {
+       struct cdunit *cdu = &cdunits[0];
+
        if (_tcscmp (changed_prefs.cdimagefile, currprefs.cdimagefile)) {
-               _tcscpy (newfile, changed_prefs.cdimagefile);
+               _tcscpy (cdu->newfile, changed_prefs.cdimagefile);
                changed_prefs.cdimagefile[0] = currprefs.cdimagefile[0] = 0;
-               imagechange = 3 * 50;
-               write_log (L"CD: eject\n");
-               unload_image ();
-               scsi_do_disk_change (-1, 0);
+               cdu->imagechange = 3 * 50;
+               unload_image (cdu);
+               int pollmode = 0;
+               scsi_do_disk_change (-1, 0, &pollmode);
+               if (pollmode)
+                       cdu->imagechange = 8 * 50;
+               write_log (L"CD: eject (%s)\n", pollmode ? L"slow" : L"fast");
 #ifdef RETROPLATFORM
                rp_cd_image_change (0, NULL); 
 #endif
        }
-       if (imagechange == 0)
+       if (cdu->imagechange == 0)
                return;
-       imagechange--;
-       if (imagechange > 0)
+       cdu->imagechange--;
+       if (cdu->imagechange > 0)
                return;
-       _tcscpy (currprefs.cdimagefile, newfile);
-       _tcscpy (changed_prefs.cdimagefile, newfile);
-       newfile[0] = 0;
+       _tcscpy (currprefs.cdimagefile, cdu->newfile);
+       _tcscpy (changed_prefs.cdimagefile, cdu->newfile);
+       cdu->newfile[0] = 0;
        write_log (L"CD: delayed insert '%s'\n", currprefs.cdimagefile[0] ? currprefs.cdimagefile : L"<EMPTY>");
        if (currprefs.scsi) {
-               donotmountme = 1;
+               cdu->donotmountme = 1;
                int un = scsi_do_disk_device_change ();
-               donotmountme = 0;
+               cdu->donotmountme = 0;
                if (un < 0) {
-                       donotmountme = -1;
+                       cdu->donotmountme = -1;
                        device_func_init (DEVICE_TYPE_ANY); // activate us again
-                       donotmountme = 0;
-                       parse_image ();
-                       scsi_do_disk_change (255, 1);
+                       cdu->donotmountme = 0;
+                       parse_image (cdu);
+                       scsi_do_disk_change (255, 1, NULL);
                }
        } else {
-               mountme (true);
+               mountme (cdu, true);
        }
 #ifdef RETROPLATFORM
        rp_cd_image_change (0, currprefs.cdimagefile);
@@ -1120,24 +1207,57 @@ void cdimage_vsync (void)
 
 static int ismedia (int unitnum, int quick)
 {
-       if (unitnum)
+       struct cdunit *cdu = &cdunits[unitnum];
+       if (!cdu->enabled)
                return -1;
-       return tracks > 0 ? 1 : 0;
+       return cdu->tracks > 0 ? 1 : 0;
+}
+
+static struct device_info *info_device (int unitnum, struct device_info *di, int quick)
+{
+       struct cdunit *cdu = &cdunits[unitnum];
+       if (!cdu->enabled)
+               return 0;
+       di->removable = 1;
+       di->bus = unitnum;
+       di->target = 0;
+       di->lun = 0;
+       di->media_inserted = 0;
+       di->bytespersector = 2048;
+       di->mediapath[0] = 0;
+       di->cylinders = 1;
+       di->trackspercylinder = 1;
+       di->sectorspertrack = cdu->cdsize / di->bytespersector;
+       if (ismedia (unitnum, 1)) {
+               di->media_inserted = 1;
+               _tcscpy (di->mediapath, currprefs.cdimagefile);
+       }
+       memset (&di->toc, 0, sizeof (struct cd_toc_head));
+       struct cd_toc_head *th = command_toc (unitnum);
+       if (th)
+               memcpy (&di->toc, th, sizeof (struct cd_toc_head));
+       di->write_protected = 1;
+       di->type = INQ_ROMD;
+       di->id = 255;
+       _tcscpy (di->label, L"CDEMU");
+       return di;
 }
 
 static int check_bus (int flags)
 {
+       struct cdunit *cdu = &cdunits[0];
+       cdu->enabled = true;
        if (!(flags & DEVICE_TYPE_CHECKAVAIL))
                return 1;
-       if (donotmountme > 0)
-               return 0;
-       if (donotmountme < 0)
+       if (cdu->donotmountme < 0 || (flags & DEVICE_TYPE_ALLOWEMU))
                return 1;
-       if (imagechange)
+       if (cdu->donotmountme > 0)
+               return 0;
+       if (cdu->imagechange)
                return 1;
        int v = currprefs.cdimagefile[0] ? 1 : 0;
        if (v) {
-               if (mountme (false) < 0) // is it supported <drive letter:>\?
+               if (mountme (cdu, false) < 0) // is it supported <drive letter:>\?
                        return 0;
        }
        if (currprefs.cdimagefileuse) {
@@ -1148,14 +1268,15 @@ static int check_bus (int flags)
 
 static int open_bus (int flags)
 {
+       struct cdunit *cdu = &cdunits[0];
        if (!(flags & DEVICE_TYPE_CHECKAVAIL))
                return 1;
-       if (donotmountme > 0)
-               return 0;
-       if (donotmountme < 0)
+       if (cdu->donotmountme < 0 || (flags & DEVICE_TYPE_ALLOWEMU))
                return 1;
+       if (cdu->donotmountme > 0)
+               return 0;
 
-       mountme (true);
+       mountme (cdu, true);
 #ifdef RETROPLATFORM
        rp_cd_change (0, 0);
        rp_cd_image_change (0, currprefs.cdimagefile);
@@ -1165,37 +1286,11 @@ static int open_bus (int flags)
 
 static void close_bus (void)
 {
-       mp3decoder_close ();
 #ifdef RETROPLATFORM
        rp_cd_change (0, 1);
 #endif
 }
 
-static struct device_info *info_device (int unitnum, struct device_info *di)
-{
-       if (unitnum)
-               return 0;
-       di->removable = 1;
-       di->bus = unitnum;
-       di->target = 0;
-       di->lun = 0;
-       di->media_inserted = 0;
-       di->bytespersector = 2048;
-       di->mediapath[0] = 0;
-       di->cylinders = 1;
-       di->trackspercylinder = 1;
-       di->sectorspertrack = cdsize / di->bytespersector;
-       if (ismedia (unitnum, 1)) {
-               di->media_inserted = 1;
-               _tcscpy (di->mediapath, currprefs.cdimagefile);
-       }
-       di->write_protected = 1;
-       di->type = INQ_ROMD;
-       di->id = 255;
-       _tcscpy (di->label, L"IMG_EMU");
-       return di;
-}
-
 struct device_functions devicefunc_cdimage = {
        check_bus, open_bus, close_bus, open_device, close_device, info_device,
        0, 0, 0,
index 0f09c16277f48d81e5e8fb137db18612b1b91678..eda5756f9d482c6fa3e272ec2800e2f0daa9dbd6 100644 (file)
--- a/cdtv.cpp
+++ b/cdtv.cpp
@@ -3,7 +3,7 @@
 *
 * CDTV DMAC/CDROM controller emulation
 *
-* Copyright 2004/2007 Toni Wilen
+* Copyright 2004/2007-2010 Toni Wilen
 *
 * Thanks to Mark Knibbs <markk@clara.co.uk> for CDTV Technical information
 *
@@ -11,6 +11,7 @@
 
 //#define ROMHACK
 //#define ROMHACK2
+//#define CDTV_SUB_DEBUG
 //#define CDTV_DEBUG
 //#define CDTV_DEBUG_CMD
 //#define CDTV_DEBUG_6525
 #define ISTR_FF_FLG             (1<<1)
 #define ISTR_FE_FLG             (1<<0)
 
-#define AUDIO_STATUS_NOT_SUPPORTED  0x00
-#define AUDIO_STATUS_IN_PROGRESS    0x11
-#define AUDIO_STATUS_PAUSED         0x12
-#define AUDIO_STATUS_PLAY_COMPLETE  0x13
-#define AUDIO_STATUS_PLAY_ERROR     0x14
-#define AUDIO_STATUS_NO_STATUS      0x15
-
 #define MODEL_NAME "MATSHITA0.96"
 /* also MATSHITA0.97 exists but is apparently rare */
 
+#define MAX_SUBCODEBUFFER 16
+static volatile int subcodebufferoffset, subcodebufferoffsetw, subcodeoffset;
+static uae_u8 subcodebufferinuse[MAX_SUBCODEBUFFER];
+static uae_u8 subcodebuffer[MAX_SUBCODEBUFFER * SUB_CHANNEL_SIZE];
+static uae_sem_t sub_sem;
+
 static smp_comm_pipe requests;
 static volatile int thread_alive;
 
 static int configured;
 static uae_u8 dmacmemory[100];
 
-#define        MAX_TOC_ENTRIES 103
-static uae_u8 cdrom_toc[MAX_TOC_ENTRIES * 13];
+static struct cd_toc_head toc;
 static uae_u32 last_cd_position, play_start, play_end;
-static uae_u8 cdrom_qcode[16], cd_audio_status;
+static uae_u8 cdrom_qcode[4 + 12], cd_audio_status;
 static int datatrack;
 
-static volatile int cdtv_command_len;
-static volatile uae_u8 cdtv_command_buf[6];
 static volatile uae_u8 dmac_istr, dmac_cntr;
 static volatile uae_u16 dmac_dawr;
 static volatile uae_u32 dmac_acr;
 static volatile int dmac_wtc;
 static volatile int dmac_dma;
 
-static volatile int activate_stch, cdrom_command_done, play_state, play_state_cmd, play_statewait;
+static volatile int activate_stch, cdrom_command_done, play_state, play_statewait;
 static volatile int cdrom_sector, cdrom_sectors, cdrom_length, cdrom_offset;
 static volatile int cd_playing, cd_paused, cd_motor, cd_media, cd_error, cd_finished, cd_isready, cd_hunt;
 static uae_u32 last_play_pos, last_play_end;
@@ -87,8 +84,15 @@ static uae_u32 last_play_pos, last_play_end;
 static volatile int cdtv_hsync, dma_finished, cdtv_sectorsize;
 static volatile uae_u64 dma_wait;
 static int first;
-static int cd_volume;
+static int cd_volume, cd_volume_stored;
 static int cd_led;
+static int frontpanel;
+
+static uae_u8 cdrom_command_input[16];
+static int cdrom_command_cnt_in;
+
+static uae_u8 tp_a, tp_b, tp_c, tp_ad, tp_bd, tp_cd;
+static uae_u8 tp_imask, tp_cr, tp_air, tp_ilatch, tp_ilatch2;
 
 #ifdef ROMHACK
 #define ROM_VECTOR 0x2000
@@ -115,39 +119,26 @@ static volatile int cmd, enable, xaen, dten;
 
 static int unitnum = -1;
 
-/* convert minutes, seconds and frames -> logical sector number */
-static int msf2lsn (int        msf)
+static void subreset (void)
 {
-       int sector = ((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff);
-       if (sector < 0)
-               sector = 0;
-       return sector;
-}
-
-/* convert logical sector number -> minutes, seconds and frames */
-static int lsn2msf (int        sectors)
-{
-       int msf;
-       msf = (sectors / (75 * 60)) << 16;
-       msf |= ((sectors / 75) % 60) << 8;
-       msf |= (sectors % 75) << 0;
-       return msf;
+       uae_sem_wait (&sub_sem);
+       memset (subcodebufferinuse, 0, sizeof subcodebufferinuse);
+       subcodebufferoffsetw = subcodebufferoffset = 0;
+       subcodeoffset = -1;
+       sbcp = 0;
+       scor = 0;
+       uae_sem_post (&sub_sem);
 }
 
 static int get_toc (void)
 {
-       uae_u8 *buf;
-       int i;
-
        datatrack = 0;
-       buf = sys_command_cd_toc (DF_IOCTL, unitnum);
-       if (!buf)
+       struct cd_toc_head *t = sys_command_cd_toc (DF_IOCTL, unitnum);
+       if (!t)
                return 0;
-       i = (buf[0] << 8) | (buf[1] << 0);
-       memcpy (cdrom_toc, buf, i);
-       last_cd_position = (buf[4 + 2 * 11 + 8] << 16) | (buf[4 + 2 * 11 + 9] << 8) | (buf[4 + 2 * 11 + 10] << 0);
-       last_cd_position = lsn2msf (msf2lsn (last_cd_position) - 1);
-       if (buf[4 + 3 * 11 + 3] == 1 && (buf[4 + 3 * 11 + 1] & 0x0c) == 0x04)
+       memcpy (&toc, t, sizeof toc);
+       last_cd_position = toc.lastaddress;
+       if (toc.first_track == 1 && (toc.toc[toc.first_track_offset].control & 0x0c) == 0x04)
                datatrack = 1;
        return 1;
 }
@@ -163,41 +154,43 @@ static void finished_cdplay (void)
 
 static int get_qcode (void)
 {
-       uae_u8 *s;
-       static uae_u8 subq0;
-
-       memset (cdrom_qcode, 0, 16);
-       s = sys_command_cd_qcode (DF_IOCTL, unitnum);
-       if (!s)
+       if (!sys_command_cd_qcode (DF_IOCTL, unitnum, cdrom_qcode))
                return 0;
-       memcpy (cdrom_qcode, s, 16);
        if (cd_playing) {
-               if (s[1] == AUDIO_STATUS_IN_PROGRESS) {
-                       int end = msf2lsn ((s[5 + 4] << 16) | (s[6 + 4] << 8) | (s[7 + 4]));
+               if (cdrom_qcode[1] == AUDIO_STATUS_IN_PROGRESS) {
+                       int end = msf2lsn (fromlongbcd (cdrom_qcode + 4 + 7));
                        if (end >= play_end - 75)
                                finished_cdplay ();
-               } else if (s[1] == AUDIO_STATUS_PLAY_COMPLETE) {
+               } else if (cdrom_qcode[1] == AUDIO_STATUS_PLAY_COMPLETE) {
                        finished_cdplay ();
                }
        }
-       s[1] = cd_audio_status;
+       cdrom_qcode[1] = cd_audio_status;
        return 1;
 }
 
 static void cdaudiostop (void)
 {
        cd_finished = 0;
-       if (cd_playing)
+       cd_audio_status = AUDIO_STATUS_NO_STATUS;
+       if (cd_playing) {
+               cd_audio_status = AUDIO_STATUS_PLAY_COMPLETE;
                cd_finished = 1;
+       }
        cd_playing = 0;
        cd_paused = 0;
        cd_motor = 0;
-       cd_audio_status = AUDIO_STATUS_NO_STATUS;
        if (unitnum < 0)
                return;
        sys_command_cd_pause (DF_IOCTL, unitnum, 0);
        sys_command_cd_stop (DF_IOCTL, unitnum);
 }
+static void cdaudiostopfp (void)
+{
+       cdaudiostop ();
+       cd_error = 1;
+       cd_audio_status = AUDIO_STATUS_PLAY_ERROR;
+}
 
 static int pause_audio (int pause)
 {
@@ -209,6 +202,7 @@ static int pause_audio (int pause)
        }
        cd_paused = pause;
        cd_audio_status = pause ? AUDIO_STATUS_PAUSED : AUDIO_STATUS_IN_PROGRESS;
+       subreset ();
        return 1;
 }
 
@@ -235,11 +229,65 @@ static int ismedia (void)
        return sys_command_ismedia (DF_IOCTL, unitnum, 0);
 }
 
+static int issub (void)
+{
+       return 1;
+}
+
+static void subfunc (uae_u8 *data, int cnt)
+{
+       if (!issub ())
+               return;
+       uae_sem_wait (&sub_sem);
+#ifdef CDTV_SUB_DEBUG
+       int total = 0;
+       for (int i = 0; i < MAX_SUBCODEBUFFER; i++) {
+               if (subcodebufferinuse[i])
+                       total++;
+       }
+       write_log (L"%d ", total);
+#endif
+       if (subcodebufferinuse[subcodebufferoffsetw]) {
+               memset (subcodebufferinuse, 0, sizeof subcodebufferinuse);
+               subcodebufferoffsetw = subcodebufferoffset = 0;
+               subcodeoffset = -1;
+               uae_sem_post (&sub_sem);
+#ifdef CDTV_SUB_DEBUG
+               write_log (L"CDTV: subcode buffer overflow 1\n");
+#endif
+               return;
+       }
+       int offset = subcodebufferoffsetw;
+       while (cnt > 0) {
+               if (subcodebufferinuse[offset]) {
+#ifdef CDTV_SUB_DEBUG
+                       write_log (L"CDTV: subcode buffer overflow 2\n");
+#endif
+                       break;
+               }
+               subcodebufferinuse[offset] = 1;
+               memcpy (&subcodebuffer[offset * SUB_CHANNEL_SIZE], data, SUB_CHANNEL_SIZE);
+               data += SUB_CHANNEL_SIZE;
+               offset++;
+               if (offset >= MAX_SUBCODEBUFFER)
+                       offset = 0;
+               cnt--;
+       }
+       subcodebufferoffsetw = offset;
+       uae_sem_post (&sub_sem);
+}
+
+
 static void do_play (void)
 {
+       uae_u32 start = read_comm_pipe_u32_blocking (&requests);
+       uae_u32 end = read_comm_pipe_u32_blocking (&requests);
+       uae_u32 scan = read_comm_pipe_u32_blocking (&requests);
+       subreset ();
        sys_command_cd_pause (DF_IOCTL, unitnum, 0);
        cd_audio_status = AUDIO_STATUS_PLAY_ERROR;
-       if (sys_command_cd_play (DF_IOCTL, unitnum, lsn2msf (play_start), lsn2msf (play_end), 0)) {
+       sys_command_cd_volume (DF_IOCTL, unitnum, (cd_volume_stored << 6) | (cd_volume_stored >> 4));
+       if (sys_command_cd_play (DF_IOCTL, unitnum, start, end, 0, subfunc)) {
                cd_audio_status = AUDIO_STATUS_IN_PROGRESS;
                cd_playing = 1;
        } else {
@@ -256,21 +304,21 @@ static int play_cdtrack (uae_u8 *p)
        int index_end = p[4];
        int start_found, end_found;
        uae_u32 start, end;
-       int i, j;
+       int j;
+
+       if (track_start == 0 && track_end == 0)
+               return 0;
 
-       i = (cdrom_toc[0] << 8) | (cdrom_toc[1] << 0);
-       i -= 2;
-       i /= 11;
        end = last_cd_position;
        start_found = end_found = 0;
-       for (j = 0; j < i; j++) {
-               uae_u8 *s = cdrom_toc + 4 + j * 11;
-               if (track_start == s[3]) {
+       for (j = 0; j < toc.points; j++) {
+               struct cd_toc *s = &toc.toc[j];
+               if (track_start == s->track) {
                        start_found++;
-                       start = (s[8] << 16) | (s[9] << 8) | s[10];
+                       start = s->paddress;
                }
-               if (track_end == s[3]) {
-                       end = (s[8] << 16) | (s[9] << 8) | s[10];
+               if (track_end == s->track) {
+                       end = s->paddress;
                        end_found++;
                }
        }
@@ -281,17 +329,15 @@ static int play_cdtrack (uae_u8 *p)
                write_log (L"PLAY CD AUDIO: illegal start track %d\n", track_start);
                return 0;
        }
-       play_end = msf2lsn (end);
-       play_start = msf2lsn (start);
-       last_play_end = start;
+       play_end = end;
+       play_start = start;
+       last_play_pos = start;
        last_play_end = end;
 #ifdef CDTV_DEBUG
        write_log (L"PLAY CD AUDIO from %d-%d, %06X (%d) to %06X (%d)\n",
-               track_start, track_end,
-               start, msf2lsn (start), end, msf2lsn (end));
+               track_start, track_end, start, start, end, end);
 #endif
        play_state = 1;
-       play_state_cmd = 1;
        return 0;
 }
 
@@ -318,21 +364,20 @@ static int play_cd (uae_u8 *p)
                cd_error = 1;
                return 0;
        }
-       if (p[0] == 0x09) { /* lsn */
-               start = lsn2msf (start);
+       if (p[0] != 0x09) { /* msf */
+               start = msf2lsn (start);
                if (end < 0x00ffffff)
-                       end = lsn2msf (end);
+                       end = msf2lsn (end);
        }
-       if (end == 0x00ffffff || end > last_cd_position)
+       if (end >= 0x00ffffff || end > last_cd_position)
                end = last_cd_position;
-       play_end = msf2lsn (end);
-       play_start = msf2lsn (start);
+       play_end = end;
+       play_start = start;
 #ifdef CDTV_DEBUG
        write_log (L"PLAY CD AUDIO from %06X (%d) to %06X (%d)\n",
-               start, msf2lsn (start), end, msf2lsn (end));
+               lsn2msf (start), start, lsn2msf (end), end);
 #endif
        play_state = 1;
-       play_state_cmd = 1;
        return 0;
 }
 
@@ -342,14 +387,13 @@ static int cdrom_subq (uae_u8 *out, int msflsn)
        uae_u32 trackposlsn, trackposmsf;
        uae_u32 diskposlsn, diskposmsf;
 
-       get_qcode ();
        out[0] = cd_audio_status;
        s += 4;
-       out[1] = s[1];
-       out[2] = s[2];
-       out[3] = s[3];
-       trackposmsf = (s[9] << 16) | (s[10] << 8) | s[11];
-       diskposmsf = (s[5] << 16) | (s[6] << 8) | s[7];
+       out[1] = (s[0] >> 4) | (s[0] << 4);
+       out[2] = frombcd (s[1]); // track
+       out[3] = frombcd (s[2]); // index
+       trackposmsf = fromlongbcd (s + 3);
+       diskposmsf = fromlongbcd (s + 7);
        trackposlsn = msf2lsn (trackposmsf);
        diskposlsn = msf2lsn (diskposmsf);
        out[4] = 0;
@@ -366,21 +410,14 @@ static int cdrom_subq (uae_u8 *out, int msflsn)
 
 static int cdrom_info (uae_u8 *out)
 {
-       uae_u8 *p;
        uae_u32 size;
-       int i;
 
        if (ismedia () <= 0)
                return -1;
        cd_motor = 1;
-       out[0] = cdrom_toc[2];
-       i = (cdrom_toc[0] << 8) | (cdrom_toc[1] << 0);
-       i -= 2 + 11;
-       i /= 11;
-       p = cdrom_toc + 4 + i * 11;
-       out[1] = p[3];
-       p = cdrom_toc + 4 + 2 * 11;
-       size =  ((p[8] << 16) | (p[9] << 8) | p[10]);
+       out[0] = toc.first_track;
+       out[1] = toc.last_track;
+       size = lsn2msf (toc.lastaddress);
        out[2] = size >> 16;
        out[3] = size >> 8;
        out[4] = size >> 0;
@@ -390,26 +427,21 @@ static int cdrom_info (uae_u8 *out)
 
 static int read_toc (int track, int msflsn, uae_u8 *out)
 {
-       uae_u8 *buf = cdrom_toc, *s;
-       int i, j;
+       int j;
 
        if (ismedia () <= 0)
                return -1;
        if (!out)
                return 0;
        cd_motor = 1;
-       i = (buf[0] << 8) | (buf[1] << 0);
-       i -= 2;
-       i /= 11;
-       for (j = 0; j < i; j++) {
-               s = buf + 4 + j * 11;
-               if (track == s[3]) {
-                       uae_u32 msf = (s[8] << 16) | (s[9] << 8) | s[10];
-                       uae_u32 lsn = msf2lsn (msf);
+       for (j = 0; j < toc.points; j++) {
+               if (track == toc.toc[j].point) {
+                       int lsn = toc.toc[j].paddress;
+                       int msf = lsn2msf (lsn);
                        out[0] = 0;
-                       out[1] = s[1];
-                       out[2] = s[3];
-                       out[3] = buf[3];
+                       out[1] = (toc.toc[j].adr << 4) | (toc.toc[j].control << 0);
+                       out[2] = toc.toc[j].point;
+                       out[3] = toc.tracks;
                        out[4] = 0;
                        out[5] = (msflsn ? msf : lsn) >> 16;
                        out[6] = (msflsn ? msf : lsn) >> 8;
@@ -457,8 +489,6 @@ static void cdrom_command_accepted (int size, uae_u8 *cdrom_command_input, int *
 
 static void cdrom_command_thread (uae_u8 b)
 {
-       static uae_u8 cdrom_command_input[16];
-       static int cdrom_command_cnt_in;
        uae_u8 *s;
 
        cdrom_command_input[cdrom_command_cnt_in] = b;
@@ -509,17 +539,17 @@ static void cdrom_command_thread (uae_u8 b)
                if (cdrom_command_cnt_in == 1) {
                        uae_u8 flag = 0;
                        if (!cd_isready)
-                               flag |= 1 << 0;
+                               flag |= 1 << 0; // 01
                        if (cd_playing)
-                               flag |= 1 << 2;
+                               flag |= 1 << 2; // 04
                        if (cd_finished)
-                               flag |= 1 << 3;
+                               flag |= 1 << 3; // 08
                        if (cd_error)
-                               flag |= 1 << 4;
+                               flag |= 1 << 4; // 10
                        if (cd_motor)
-                               flag |= 1 << 5;
+                               flag |= 1 << 5; // 20
                        if (cd_media)
-                               flag |= 1 << 6;
+                               flag |= 1 << 6; // 40
                        cdrom_command_output[0] = flag;
                        cdrom_command_accepted (1, s, &cdrom_command_cnt_in);
                        cd_finished = 0;
@@ -573,6 +603,7 @@ static void cdrom_command_thread (uae_u8 b)
                break;
        case 0xa3: /* front panel */
                if (cdrom_command_cnt_in == 7) {
+                       frontpanel = s[1] ? 1 : 0;
                        cdrom_command_accepted (0, s, &cdrom_command_cnt_in);
                        cd_finished = 1;
                }
@@ -594,15 +625,14 @@ static uae_u8 *read_raw (int sector, int size)
        TCHAR fname[MAX_DPATH];
        static uae_u8 buf[4096];
        uae_u32 prevlsn = 0;
-       uae_u8 *s = cdrom_toc + 4;
+       struct cd_toc *t = &toc.toc[0];
 
        memset (buf, 0, sizeof buf);
        trackcnt = 0;
        for (;;) {
-               uae_u32 msf = (s[8] << 16) | (s[9] << 8) | s[10];
-               uae_u32 lsn = msf2lsn (msf);
-               if (s[3] >= 0xa0) {
-                       s += 11;
+               int lsn = t->paddress;
+               if (t->point >= 0xa0) {
+                       t++;
                        continue;
                }
                if (sector < lsn - prevlsn)
@@ -610,7 +640,7 @@ static uae_u8 *read_raw (int sector, int size)
                trackcnt++;
                sector -= lsn - prevlsn;
                prevlsn = lsn;
-               s += 11;
+               t++;
        }
        if (track != trackcnt) {
                _stprintf (fname, L"track%d.bin", trackcnt);
@@ -626,7 +656,7 @@ static uae_u8 *read_raw (int sector, int size)
                zfile_fread (buf, size, 1, f);
                return buf;
        }
-       return sys_command_cd_rawread (DF_IOCTL, unitnum, osector, size);
+       return sys_command_cd_rawread (DF_IOCTL, unitnum, NULL, osector, size, 1);
 }
 
 static void dma_do_thread (void)
@@ -652,7 +682,7 @@ static void dma_do_thread (void)
                        if (cdtv_sectorsize == 2336)
                                p = read_raw (readsector, cdtv_sectorsize);
                        else
-                               p = sys_command_cd_read (DF_IOCTL, unitnum, readsector);
+                               p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, readsector, 1);
                        if (!p) {
                                cd_error = 1;
                                activate_stch = 1;
@@ -697,10 +727,12 @@ static void *dev_thread (void *p)
                        {
                                int m = ismedia ();
                                if (m < 0) {
-                                       write_log (L"CDTV: device lost\n");
-                                       activate_stch = 1;
-                                       cd_hunt = 1;
-                                       cd_media = 0;
+                                       if (!cd_hunt) {
+                                               write_log (L"CDTV: device %d lost\n", unitnum);
+                                               activate_stch = 1;
+                                               cd_hunt = 1;
+                                               cd_media = 0;
+                                       }
                                } else if (m != cd_media) {
                                        cd_media = m;
                                        get_toc ();
@@ -723,6 +755,15 @@ static void *dev_thread (void *p)
                case 0x0104: // stop
                        cdaudiostop ();
                        break;
+               case 0x0105: // pause
+                       pause_audio (1);
+                       break;
+               case 0x0106: // unpause
+                       pause_audio (0);
+                       break;
+               case 0x0107: // frontpanel stop
+                       cdaudiostopfp ();
+                       break;
                case 0x0110: // do_play!
                        do_play ();
                        break;
@@ -739,30 +780,116 @@ static void cdrom_command (uae_u8 b)
        write_comm_pipe_u32 (&requests, b, 1);
 }
 
-static uae_u8 tp_a, tp_b, tp_c, tp_ad, tp_bd, tp_cd;
-static uae_u8 tp_imr, tp_cr, tp_air;
+static void init_play (int start, int end)
+{
+       play_end = end;
+       play_start = start;
+       last_play_pos = start;
+       last_play_end = end;
+#ifdef CDTV_DEBUG
+       write_log (L"PLAY CD AUDIO from %d-%d, %06X (%d) to %06X (%d)\n",
+               track_start, track_end, lsn2msf (start), start, lsn2msf (end), end);
+#endif
+       play_state = 1;
+       subreset ();
+}
+
+bool cdtv_front_panel (int button)
+{
+       if (!frontpanel || !configured)
+               return false;
+       if (button < 0)
+               return true;
+       switch (button)
+       {
+       case 0: // stop
+               if (cd_paused)
+                       write_comm_pipe_u32 (&requests, 0x0106, 1);
+               write_comm_pipe_u32 (&requests, 0x0107, 1);
+       break;
+       case 1: // playpause
+               if (cd_playing)  {
+                       write_comm_pipe_u32 (&requests, cd_paused ? 0x0106 : 0x0105, 1);
+               } else if (cd_media) {
+                       init_play (0, last_cd_position);
+               }
+       break;
+       case 2: // prev
+       case 3: // next
+       if (!cd_playing)
+               return true;
+       uae_u8 *sq = cdrom_qcode + 4;
+       int track = frombcd (sq[1]);
+       int pos = 0;
+       for (int j = 0; j < toc.points; j++) {
+               int t = toc.toc[j].track;
+               pos = toc.toc[j].paddress;
+               if (t == 1 && track == 1 && button == 2)
+                       break;
+               else if (j == toc.points - 1 && t == track && button == 3)
+                       break;
+               else if (t == track - 1 && track > 1 && button == 2)
+                       break;
+               else if (t == track + 1 && track < 99 && button == 3)
+                       break;
+       }
+       init_play (pos - 150, last_cd_position);
+       break;
+       }
+       return true;
+}
+
+static uae_u8 get_tp_c (void)
+{
+       uae_u8 v = (sbcp ? 0 : (1 << 0)) | (scor ? 0 : (1 << 1)) |
+               (stch ? 0 : (1 << 2)) | (sten ? 0 : (1 << 3) | (1 << 4));
+       return v;
+}
+static uae_u8 get_tp_c_level (void)
+{
+       uae_u8 v = (sbcp == 1 ? 0 : (1 << 0)) | (scor == 1 ? 0 : (1 << 1)) |
+               (stch == 1 ? 0 : (1 << 2)) | (sten == 1 ? 0 : (1 << 3)) | (1 << 4);
+       if (sten == 1)
+               sten = -1;
+       if (scor == 1)
+               scor = -1;
+       if (sbcp == 1)
+               sbcp = -1;
+       return v;
+}
 
 static void tp_check_interrupts (void)
 {
        /* MC = 1 ? */
-       if ((tp_cr & 1) != 1)
+       if ((tp_cr & 1) != 1) {
+               get_tp_c_level ();
                return;
+       }
 
-       if (sten == 1) {
-               sten = -1;
-               if (tp_cd & (1 << 3))
-                       tp_air |= 1 << 3;
+       tp_ilatch |= get_tp_c_level () ^ 0x1f;
+       stch = 0;
+       if (!(tp_ilatch & (1 << 5)) && (tp_ilatch & tp_imask)) {
+               tp_air = 0;
+               int mask = 0x10;
+               while (((tp_ilatch & tp_imask) & mask) == 0)
+                       mask >>= 1;
+               tp_air |= tp_ilatch & mask;
+               tp_ilatch |= 1 << 5; // IRQ
+               tp_ilatch2 = tp_ilatch & mask;
+               tp_ilatch &= ~mask;
        }
-       if ((tp_air & tp_cd) & 0x1f)
+       if (tp_ilatch & (1 << 5))
                INT2 ();
 }
 
+// MC=1, C lines 0-4 = input irq lines, 5 = irq out, 6-7 IO
 
 static void tp_bput (int addr, uae_u8 v)
 {
        static int volstrobe1, volstrobe2;
 #ifdef CDTV_DEBUG_6525
-       write_log (L"6525 write %x=%02X PC=%x\n", addr, v, M68K_GETPC);
+       if (addr != 1)
+               write_log (L"6525 write %x=%02X PC=%x %d\n", addr, v, M68K_GETPC, regs.s);
 #endif
        switch (addr)
        {
@@ -773,8 +900,15 @@ static void tp_bput (int addr, uae_u8 v)
                tp_b = v;
                break;
        case 2:
-               if (!(tp_cr & 1))
-                       tp_c = v;
+               if (tp_cr & 1) {
+                       // 0 = clear, 1 = ignored
+                       tp_ilatch &= 0xe0 | v;
+               } else {
+                       tp_c = get_tp_c () & ~tp_cd;
+                       tp_c |= v & tp_cd;
+                       if (tp_c & (1 << 5))
+                               INT2 ();
+               }
                break;
        case 3:
                tp_ad = v;
@@ -783,7 +917,12 @@ static void tp_bput (int addr, uae_u8 v)
                tp_bd = v;
                break;
        case 5:
-               tp_cd = v;
+               // data direction (mode=0), interrupt mask (mode=1)
+               if (tp_cr & 1) {
+                       tp_imask = v & 0x1f;
+               } else {
+                       tp_cd = v;
+               }
                break;
        case 6:
                tp_cr = v;
@@ -812,35 +951,56 @@ static void tp_bput (int addr, uae_u8 v)
                        cd_volume = 1023;
                if (unitnum >= 0)
                        sys_command_cd_volume (DF_IOCTL, unitnum, (cd_volume << 6) | (cd_volume >> 4));
+               cd_volume_stored = cd_volume;
                cd_volume = 0;
                volstrobe2 = 1;
        } else if (volstrobe2 && !((tp_b >> 7) & 1)) {
                volstrobe2 = 0;
        }
+       tp_check_interrupts ();
 }
 
+static uae_u8 subtransferbuf[SUB_CHANNEL_SIZE];
+
 static uae_u8 tp_bget (int addr)
 {
        uae_u8 v = 0;
        switch (addr)
        {
        case 0:
-               v = tp_a;
-               write_log (L"TPA read!\n");
+               // A = subchannel byte input from serial to parallel converter
+               if (subcodeoffset < 0 || subcodeoffset >= SUB_CHANNEL_SIZE) {
+#ifdef CDTV_SUB_DEBUG
+                       write_log (L"CDTV: requested non-existing subchannel data!? %d\n", subcodeoffset);
+#endif
+                       v = 0;
+               } else {
+                       v = subtransferbuf[subcodeoffset];
+                       tp_a = 0;
+                       tp_a |= (v >> 7) & 1;
+                       tp_a |= (v >> 5) & 2;
+                       tp_a |= (v >> 3) & 4;
+                       tp_a |= (v >> 1) & 8;
+                       tp_a |= (v << 1) & 16;
+                       tp_a |= (v << 3) & 32;
+                       tp_a |= (v << 5) & 64;
+                       tp_a |= (v << 7) & 128;
+                       v = tp_a;
+                       subcodeoffset++;
+                       sbcp = 0;
+                       if (subcodeoffset >= SUB_CHANNEL_SIZE)
+                               subcodeoffset = -2;
+               }
                break;
        case 1:
                v = tp_b;
                break;
        case 2:
-               v = (sbcp << 0) | ((scor ^ 1) << 1) | ((stch ^ 1) << 2) | (sten << 3);
                if (tp_cr & 1) {
-                       if (!v)
-                               v |= 1 << 5; // /IRQ
+                       v = tp_ilatch | tp_ilatch2;
                } else {
-                       v |= tp_c & ~(0x80 | 0x40);
+                       v = get_tp_c ();
                }
-               v |= tp_c & (0x80 | 0x40);
-               sbcp = 0;
                break;
        case 3:
                v = tp_ad;
@@ -849,20 +1009,30 @@ static uae_u8 tp_bget (int addr)
                v = tp_bd;
                break;
        case 5:
-               v = tp_cd;
+               // data direction (mode=0), interrupt mask (mode=1)
+               if (tp_cr & 1)
+                       v = tp_imask;
+               else
+                       v = tp_cd;
                break;
        case 6:
                v = tp_cr;
                break;
        case 7:
                v = tp_air;
+               if (tp_cr & 1) {
+                       tp_ilatch &= ~(1 << 5);
+                       tp_ilatch2 = 0;
+               }
                tp_air = 0;
                break;
        }
 
+       tp_check_interrupts ();
+
 #ifdef CDTV_DEBUG_6525
-       if (addr < 7)
-               write_log (L"6525 read %x=%02X PC=%x\n", addr, v, M68K_GETPC);
+       if (addr < 7 && addr != 1)
+               write_log (L"6525 read %x=%02X PC=%x %d\n", addr, v, M68K_GETPC, regs.s);
 #endif
        return v;
 }
@@ -905,16 +1075,16 @@ static void do_hunt (void)
        }
        if (unitnum >= 0) {
                cdaudiostop ();
-               sys_command_close (DF_IOCTL, unitnum);
+               int ou = unitnum;
+               unitnum = -1;
+               sys_command_close (DF_IOCTL, ou);
        }
        if (sys_command_open (DF_IOCTL, i) > 0) {
                struct device_info di = { 0 };
-               sys_command_info (DF_IOCTL, i, &di);
+               sys_command_info (DF_IOCTL, i, &di, 0);
                unitnum = i;
                cd_hunt = 0;
                write_log (L"CDTV: autodetected unit %d ('%s')\n", unitnum, di.label);
-       } else {
-               unitnum = -1;
        }
 }
 
@@ -970,34 +1140,82 @@ void CDTV_hsync_handler (void)
                dma_finished = 0;
                cdtv_hsync = -1;
        }
-       checkint();
+       checkint ();
 
        if (cdrom_command_done) {
                cdrom_command_done = 0;
                sten = 1;
+               stch = 0;
                tp_check_interrupts ();
        }
 
-       if (cdtv_hsync < 312 * 50 / 75 && cdtv_hsync >= 0)
-               return;
-       cdtv_hsync = 0;
+       if (sbcp == 0 && subcodeoffset > 0) {
+               sbcp = 1;
+               tp_check_interrupts ();
+       }
 
-       if (first > 0) {
-               first--;
-               if (first == 0)
-                       do_stch ();
+       if (sten < 0) {
+               sten--;
+               if (sten < -3)
+                       sten = 0;
        }
+       if (scor < 0) {
+               scor--;
+               if (scor <= -2) {
+                       if (issub ()) {
+                               subcodeoffset = 0;
+                               sbcp = 1;
+                       }
+                       scor = 0;
+                       tp_check_interrupts ();
+               }
+       }
+
+       static int subchannelcounter;
+       if (subchannelcounter > 0)
+               subchannelcounter--;
+       if (subchannelcounter <= 0) {
+               if (cd_playing || cd_media) {
+                       if (subcodebufferoffset != subcodebufferoffsetw) {
+                               uae_sem_wait (&sub_sem);
+#ifdef CDTV_SUB_DEBUG
+                               if (subcodeoffset >= 0)
+                                       write_log (L"CDTV: frame interrupt, subchannel not empty! %d\n", subcodeoffset);
+#endif
+                               subcodeoffset = -1;
+                               if (subcodebufferinuse[subcodebufferoffset]) {
+                                       subcodebufferinuse[subcodebufferoffset] = 0;
+                                       memcpy (subtransferbuf, subcodebuffer + subcodebufferoffset * SUB_CHANNEL_SIZE, SUB_CHANNEL_SIZE);
+                                       subcodebufferoffset++;
+                                       if (subcodebufferoffset >= MAX_SUBCODEBUFFER)
+                                               subcodebufferoffset -= MAX_SUBCODEBUFFER;
+                                       sbcp = 0;
+                                       scor = 1;
+                                       tp_check_interrupts ();
+                               }
+                               uae_sem_post (&sub_sem);
+                               subchannelcounter = 200;
+                       }
+               }
+       }
+
+       if (cdtv_hsync < 200 && cdtv_hsync >= 0)
+               return;
+       cdtv_hsync = 0;
 
        if (play_state == 1) {
                play_state = 2;
                cd_playing = 1;
                cd_motor = 1;
                activate_stch = 1;
-               play_statewait = 5;
+               play_statewait = 2;
        } else if (play_statewait > 0) {
                play_statewait--;
        } else if (play_state == 2) {
-               write_comm_pipe_u32 (&requests, 0x0110, 1);
+               write_comm_pipe_u32 (&requests, 0x0110, 0);
+               write_comm_pipe_u32 (&requests, play_start, 0);
+               write_comm_pipe_u32 (&requests, play_end, 0);
+               write_comm_pipe_u32 (&requests, 0, 1);
                play_state = 0;
        }
 
@@ -1017,18 +1235,17 @@ void CDTV_hsync_handler (void)
        if (cd_led)
                gui_flicker_led (LED_CD, 0, cd_led);
 
-       if (cd_media && (tp_cr & 1)) {
-               tp_air |= 1 << 1;
-               INT2 ();
-       }
-
        subqcnt--;
        if (subqcnt < 0) {
                write_comm_pipe_u32 (&requests, 0x0101, 1);
-               subqcnt = 75;
+               if (cd_playing && !cd_hunt)
+                       subqcnt = 10;
+               else
+                       subqcnt = 75;
                if (cd_hunt)
                        do_hunt ();
        }
+
        if (activate_stch)
                do_stch ();
 }
@@ -1037,10 +1254,10 @@ static void do_stch (void)
 {
        static int stch_cnt;
 
-       if ((tp_cr & 1) && !(tp_air & (1 << 2)) && (tp_cd & (1 << 2))) {
+       if ((tp_cr & 1) && !(tp_air & (1 << 2))) {
+               stch = 1;
                activate_stch = 0;
-               tp_air |= 1 << 2;
-               INT2 ();
+               tp_check_interrupts ();
 #ifdef CDTV_DEBUG
                write_log (L"STCH %d\n", stch_cnt++);
 #endif
@@ -1067,12 +1284,13 @@ static void cdtv_reset (void)
        cd_error = 0;
        cd_finished = 0;
        cd_led = 0;
-       stch = 0;
+       stch = 1;
        first = -1;
 }
 
 static uae_u32 dmac_bget2 (uaecptr addr)
 {
+       static uae_u8 last_out;
        uae_u8 v = 0;
 
        if (addr < 0x40)
@@ -1113,18 +1331,22 @@ static uae_u32 dmac_bget2 (uaecptr addr)
                }
                break;
        case 0xa1:
+               sten = 0;
                if (cdrom_command_cnt_out >= 0) {
-                       v = cdrom_command_output[cdrom_command_cnt_out];
+                       v = last_out = cdrom_command_output[cdrom_command_cnt_out];
                        cdrom_command_output[cdrom_command_cnt_out++] = 0;
                        if (cdrom_command_cnt_out >= cdrom_command_size_out) {
-                               stch = 1;
-                               sten = 0;
                                cdrom_command_size_out = 0;
                                cdrom_command_cnt_out = -1;
+                               sten = 0;
+                               tp_check_interrupts ();
                        } else {
                                sten = 1;
                                tp_check_interrupts ();
                        }
+               } else {
+                       write_log (L"CDTV: command register read while empty\n");
+                       v = last_out;
                }
                break;
        case 0xe8:
@@ -1353,7 +1575,7 @@ static void open_unit (void)
                sys_command_close (DF_IOCTL, unitnum);
        unitnum = -1;
        cdtv_reset ();
-       if (!device_func_init (DEVICE_TYPE_ANY)) {
+       if (!device_func_init (DEVICE_TYPE_IOCTL)) {
                write_log (L"no CDROM support\n");
                return;
        }
@@ -1361,14 +1583,14 @@ static void open_unit (void)
                opened[unitnum] = 0;
                if (sys_command_open (DF_IOCTL, unitnum)) {
                        opened[unitnum] = 1;
-                       di2 = sys_command_info (DF_IOCTL, unitnum, &di1);
+                       di2 = sys_command_info (DF_IOCTL, unitnum, &di1, 0);
                        if (di2 && di2->type == INQ_ROMD) {
                                write_log (L"%s: ", di2->label);
                                if (first < 0)
                                        first = unitnum;
                                if (get_toc () > 0) {
                                        if (datatrack) {
-                                               uae_u8 *p = sys_command_cd_read (DF_IOCTL, unitnum, 16);
+                                               uae_u8 *p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, 16, 1);
                                                if (p) {
                                                        if (!memcmp (p + 8, "CDTV", 4)) {
                                                                write_log (L"CDTV\n");
@@ -1400,7 +1622,7 @@ static void open_unit (void)
        }
        cd_media = 0;
        if (unitnum >= 0) {
-               cd_media = ismedia () ? -1 : 0;
+               cd_media = ismedia () > 0 ? -1 : 0;
                if (!cd_media)
                        cd_hunt = 1;
                if (!get_toc())
@@ -1616,10 +1838,10 @@ void cdtv_init (void)
 
        configured = 0;
        tp_a = tp_b = tp_c = tp_ad = tp_bd = tp_cd = 0;
-       tp_imr = tp_cr = tp_air = 0;
-       stch = 1;
-       sten = 1;
-       scor = 1;
+       tp_imask = tp_cr = tp_air = tp_ilatch = 0;
+       stch = 0;
+       sten = 0;
+       scor = 0;
        sbcp = 0;
        cdrom_command_cnt_out = -1;
        cmd = enable = xaen = dten = 0;
@@ -1635,6 +1857,8 @@ void cdtv_init (void)
        ew (0x20, 0x00); /* ser.no. Byte 2 */
        ew (0x24, 0x00); /* ser.no. Byte 3 */
 
+       uae_sem_init (&sub_sem, 0, 1);
+
 #ifdef ROMHACK2
        romhack();
 #endif
@@ -1647,30 +1871,128 @@ void cdtv_init (void)
 
 #ifdef SAVESTATE
 
+uae_u8 *save_dmac (int *len)
+{
+       uae_u8 *dstbak, *dst;
+       
+       dstbak = dst = xmalloc (uae_u8, 1000);
+
+       // model (0=original,1=rev2,2=superdmac)
+       save_u32 (1);
+       save_u32 (0); // reserved flags
+       save_u8 (dmac_istr);
+       save_u8 (dmac_cntr);
+       save_u32 (dmac_wtc);
+       save_u32 (dmac_acr);
+       save_u16 (dmac_dawr);
+       save_u32 (dmac_dma ? 1 : 0);
+       *len = dst - dstbak;
+       return dstbak;
+
+}
+
+uae_u8 *restore_dmac (uae_u8 *src)
+{
+       restore_u32 ();
+       restore_u32 ();
+       dmac_istr = restore_u8 ();
+       dmac_cntr = restore_u8 ();
+       dmac_wtc = restore_u32 ();
+       dmac_acr = restore_u32 ();
+       dmac_dawr = restore_u16 ();
+       restore_u32 ();
+       return src;
+}
+
 uae_u8 *save_cdtv (int *len)
 {
        uae_u8 *dstbak, *dst;
-       int i;
 
-       if (!currprefs.cs_cd32cd)
+       if (!currprefs.cs_cdtvcd)
                return NULL;
-       return NULL;
        dstbak = dst = xmalloc (uae_u8, 1000);
+
+       save_u32 (1);
+
+       // tri-port
+       save_u8 (tp_a);
+       save_u8 (tp_b);
+       save_u8 (tp_c);
+       save_u8 (tp_ad);
+       save_u8 (tp_bd);
+       save_u8 (tp_cd);
+       save_u8 (tp_cr);
+       save_u8 (tp_air);
+       save_u8 (tp_imask);
+       save_u8 (tp_ilatch);
+       save_u8 (tp_ilatch2);
+       save_u8 (0);
+       // misc cd stuff
+       save_u32 ((cd_playing ? 1 : 0) | (cd_paused ? 2 : 0) | (cd_media ? 4 : 0) |
+               (cd_motor ? 8 : 0) | (cd_error ? 16 : 0) | (cd_finished ? 32 : 0) | (cdrom_command_done ? 64 : 0) |
+               (activate_stch ? 128 : 0) | (sten ? 256 : 0) | (stch ? 512 : 0) | (frontpanel ? 1024 : 0));
+       save_u8 (cd_isready);
+       save_u8 (play_state);
+       save_u16 (cd_volume_stored);
+       if (cd_playing)
+               get_qcode ();
+       save_u32 (last_play_pos);
+       save_u32 (last_play_end);
+       save_u64 (dma_wait);
+       for (int i = 0; i < sizeof cdrom_command_input; i++)
+               save_u8 (cdrom_command_input[i]);
+       save_u8 (cdrom_command_cnt_in);
+
        *len = dst - dstbak;
        return dstbak;
 }
 
 uae_u8 *restore_cdtv (uae_u8 *src)
 {
-       uae_u32 v;
-       int i;
-
        cdtv_free ();
        if (!currprefs.cs_cdtvcd) {
                changed_prefs.cs_cdtvcd = changed_prefs.cs_cdtvram = true;
                currprefs.cs_cdtvcd = currprefs.cs_cdtvram = true;
                cdtv_init ();
        }
+       restore_u32 ();
+       
+       // tri-port
+       tp_a = restore_u8 ();
+       tp_b = restore_u8 ();
+       tp_c = restore_u8 ();
+       tp_ad = restore_u8 ();
+       tp_bd = restore_u8 ();
+       tp_cd = restore_u8 ();
+       tp_cr = restore_u8 ();
+       tp_air = restore_u8 ();
+       tp_imask = restore_u8 ();
+       tp_ilatch = restore_u8 ();
+       tp_ilatch2 = restore_u8 ();
+       restore_u8 ();
+       // misc cd stuff
+       uae_u32 v = restore_u32 ();
+       cd_playing = (v & 1) ? 1 : 0;
+       cd_paused = (v & 2) ? 1 : 0;
+       cd_media = (v & 4) ? 1 : 0;
+       cd_motor = (v & 8) ? 1 : 0;
+       cd_error = (v & 16) ? 1 : 0;
+       cd_finished = (v & 32) ? 1 : 0;
+       cdrom_command_done = (v & 64) ? 1 : 0;
+       activate_stch = (v & 128) ? 1 : 0;
+       sten = (v & 256) ? 1 : 0;
+       stch = (v & 512) ? 1 : 0;
+       frontpanel = (v & 1024) ? 1 : 0;
+       cd_isready = restore_u8 ();
+       play_state = restore_u8 ();
+       cd_volume_stored = restore_u16 ();
+       last_play_pos = restore_u32 ();
+       last_play_end = restore_u32 ();
+       dma_wait = restore_u64 ();
+       for (int i = 0; i < sizeof cdrom_command_input; i++)
+               cdrom_command_input[i] = restore_u8 ();
+       cdrom_command_cnt_in = restore_u8 ();
+
        return src;
 }
 
index 4c63a93536c512e63ae2994a03be1f2642148946..5267e70f92921c474f146b2e4ffa09f409a844fe 100644 (file)
@@ -487,8 +487,10 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
        cfgfile_write_str (f, L"config_host_path", p->config_host_path);
 
        for (sl = p->all_lines; sl; sl = sl->next) {
-               if (sl->unknown)
-                       cfgfile_write_str (f, sl->option, sl->value);
+               if (sl->unknown) {
+                       if (sl->option)
+                               cfgfile_write_str (f, sl->option, sl->value);
+               }
        }
 
        _stprintf (tmp, L"%s.rom_path", TARGET_NAME);
@@ -552,7 +554,7 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
                }
        }
 
-       if (p->cdimagefile[0])
+       if (p->cdimagefile[0] || p->cdimagefileuse)
                cfgfile_write_str (f, L"cdimage0", p->cdimagefile);
 
        if (p->quitstatefile[0])
@@ -917,7 +919,7 @@ int cfgfile_intval (const TCHAR *option, const TCHAR *value, const TCHAR *name,
        if (_tcscmp (option, name) != 0)
                return 0;
        /* I guess octal isn't popular enough to worry about here...  */
-       if (value[0] == '0' && value[1] == 'x')
+       if (value[0] == '0' && _totupper (value[1]) == 'X')
                value += 2, base = 16;
        *location = _tcstol (value, &endptr, base) * scale;
 
@@ -2430,8 +2432,17 @@ static int cfgfile_load_2 (struct uae_prefs *p, const TCHAR *filename, bool real
        while (cfg_fgets (linea, sizeof (linea), fh) != 0) {
                trimwsa (linea);
                if (strlen (linea) > 0) {
-                       if (linea[0] == '#' || linea[0] == ';')
+                       if (linea[0] == '#' || linea[0] == ';') {
+                               struct strlist *u = xcalloc (struct strlist, 1);
+                               u->option = NULL;
+                               TCHAR *com = au (linea);
+                               u->value = my_strdup (com);
+                               xfree (com);
+                               u->unknown = 1;
+                               u->next = p->all_lines;
+                               p->all_lines = u;
                                continue;
+                       }
                        if (!cfgfile_separate_linea (linea, line1b, line2b))
                                continue;
                        type1 = type2 = 0;
index cc742de4e50d9b031503c75e05c346d054bfa681..35f6effbfc9fc3d72548f5674000306e9780eacd 100644 (file)
@@ -174,7 +174,8 @@ int maxhpos = MAXHPOS_PAL;
 int maxhpos_short = MAXHPOS_PAL;
 int maxvpos = MAXVPOS_PAL;
 int maxvpos_nom = MAXVPOS_PAL; // nominal value (same as maxvpos but "faked" maxvpos in fake 60hz modes)
-int hsyncstartpos;
+static int hsyncstartpos;
+int hsyncstartposnative;
 static int maxvpos_total = 511;
 int minfirstline = VBLANK_ENDLINE_PAL;
 int equ_vblank_endline = EQU_ENDLINE_PAL;
@@ -2496,6 +2497,7 @@ static void finish_decisions (void)
        decide_line (hpos);
        decide_fetch (hpos);
 
+       record_color_change2 (hsyncstartpos, 0xffff, 0);
        if (thisline_decision.plfleft != -1 && thisline_decision.plflinelen == -1) {
                if (fetch_state != fetch_not_started) {
                        write_log (L"fetch_state=%d plfleft=%d,len=%d,vpos=%d,hpos=%d\n",
@@ -2803,8 +2805,9 @@ void init_hz (void)
                else
                        hsyncstartpos = maxhpos + hbstrt;
        } else {
-               hsyncstartpos = maxhpos_short + 7;
+               hsyncstartpos = maxhpos_short + 13;
        }
+       hsyncstartposnative = coord_hw_to_window_x (hsyncstartpos * 2);
        eventtab[ev_hsync].oldcycles = get_cycles ();
        eventtab[ev_hsync].evtime = get_cycles () + HSYNCTIME;
        events_schedule ();
@@ -5344,6 +5347,8 @@ static void events_dmal (int hp)
                }
                event2_newevent2 (hp, dmal_hpos + ((dmal & 2) ? 1 : 0), dmal_func);
                dmal &= ~3;
+       } else if (currprefs.cachesize) {
+               dmal_func2 (0);
        } else {
                event2_newevent2 (hp, 17, dmal_func2);
        }
index ea1b487da2298ef84ee28a3bd9701f663194a277..6365e3d1ad6f3c717586d618879cd171e175dd79 100644 (file)
--- a/debug.cpp
+++ b/debug.cpp
@@ -88,63 +88,63 @@ static struct regstruct history[MAX_HIST];
 static TCHAR help[] = {
        L"          HELP for UAE Debugger\n"
        L"         -----------------------\n\n"
-       L"  g [<address>]         Start execution at the current address or <address>\n"
-       L"  c                     Dump state of the CIA, disk drives and custom registers\n"
-       L"  r                     Dump state of the CPU\n"
-       L"  r <reg> <value>       Modify CPU registers (Dx,Ax,USP,ISP,VBR,...)\n"
-       L"  m <address> [<lines>] Memory dump starting at <address>\n"
-       L"  d <address> [<lines>] Disassembly starting at <address>\n"
-       L"  t [instructions]      Step one or more instructions\n"
-       L"  z                     Step through one instruction - useful for JSR, DBRA etc\n"
-       L"  f                     Step forward until PC in RAM (\"boot block finder\")\n"
-       L"  f <address>           Add/remove breakpoint\n"
+       L"  g [<address>]         Start execution at the current address or <address>.\n"
+       L"  c                     Dump state of the CIA, disk drives and custom registers.\n"
+       L"  r                     Dump state of the CPU.\n"
+       L"  r <reg> <value>       Modify CPU registers (Dx,Ax,USP,ISP,VBR,...).\n"
+       L"  m <address> [<lines>] Memory dump starting at <address>.\n"
+       L"  d <address> [<lines>] Disassembly starting at <address>.\n"
+       L"  t [instructions]      Step one or more instructions.\n"
+       L"  z                     Step through one instruction - useful for JSR, DBRA etc.\n"
+       L"  f                     Step forward until PC in RAM (\"boot block finder\").\n"
+       L"  f <address>           Add/remove breakpoint.\n"
        L"  fa <address> [<start>] [<end>]\n"
-       L"                        Find effective address <address>\n"
-       L"  fi                    Step forward until PC points to RTS, RTD or RTE\n"
-       L"  fi <opcode>           Step forward until PC points to <opcode>\n"
-       L"  fp \"<name>\"/<addr>    Step forward until process <name> or <addr> is active\n"
-       L"  fl                    List breakpoints\n"
-       L"  fd                    Remove all breakpoints\n"
-       L"  fs <val> <mask>       Break when (SR & mask) = val\n"                   
-       L"  f <addr1> <addr2>     Step forward until <addr1> <= PC <= <addr2>\n"
-       L"  e                     Dump contents of all custom registers, ea = AGA colors\n"
-       L"  i [<addr>]            Dump contents of interrupt and trap vectors\n"
-       L"  il [<mask>]           Exception breakpoint\n"
-       L"  o <0-2|addr> [<lines>]View memory as Copper instructions\n"
-       L"  od                    Enable/disable Copper vpos/hpos tracing\n"
-       L"  ot                    Copper single step trace\n"
-       L"  ob <addr>             Copper breakpoint\n"
-       L"  H[H] <cnt>            Show PC history (HH=full CPU info) <cnt> instructions\n"
-       L"  C <value>             Search for values like energy or lifes in games\n"
-       L"  Cl                    List currently found trainer addresses\n"
+       L"                        Find effective address <address>.\n"
+       L"  fi                    Step forward until PC points to RTS, RTD or RTE.\n"
+       L"  fi <opcode>           Step forward until PC points to <opcode>.\n"
+       L"  fp \"<name>\"/<addr>    Step forward until process <name> or <addr> is active.\n"
+       L"  fl                    List breakpoints.\n"
+       L"  fd                    Remove all breakpoints.\n"
+       L"  fs <val> <mask>       Break when (SR & mask) = val.\n"                   
+       L"  f <addr1> <addr2>     Step forward until <addr1> <= PC <= <addr2>.\n"
+       L"  e                     Dump contents of all custom registers, ea = AGA colors.\n"
+       L"  i [<addr>]            Dump contents of interrupt and trap vectors.\n"
+       L"  il [<mask>]           Exception breakpoint.\n"
+       L"  o <0-2|addr> [<lines>]View memory as Copper instructions.\n"
+       L"  od                    Enable/disable Copper vpos/hpos tracing.\n"
+       L"  ot                    Copper single step trace.\n"
+       L"  ob <addr>             Copper breakpoint.\n"
+       L"  H[H] <cnt>            Show PC history (HH=full CPU info) <cnt> instructions.\n"
+       L"  C <value>             Search for values like energy or lifes in games.\n"
+       L"  Cl                    List currently found trainer addresses.\n"
        L"  D[idxzs <[max diff]>] Deep trainer. i=new value must be larger, d=smaller,\n"
        L"                        x = must be same, z = must be different, s = restart.\n"
-       L"  W <address> <value>   Write into Amiga memory\n"
-       L"  w <num> <address> <length> <R/W/I/F/C> [<value>] (read/write/opcode/freeze/mustchange)\n"
-       L"                        Add/remove memory watchpoints\n"
+       L"  W <address> <value[.x]> Write into Amiga memory.\n"
+       L"  w <num> <address> <length> <R/W/I/F/C> [<value>[.x]] (read/write/opcode/freeze/mustchange).\n"
+       L"                        Add/remove memory watchpoints.\n"
        L"  wd [<0-1>]            Enable illegal access logger. 1 = enable break.\n"
-       L"  S <file> <addr> <n>   Save a block of Amiga memory\n"
+       L"  S <file> <addr> <n>   Save a block of Amiga memory.\n"
        L"  s \"<string>\"/<values> [<addr>] [<length>]\n"
-       L"                        Search for string/bytes\n"
-       L"  T or Tt               Show exec tasks and their PCs\n"
-       L"  Td,Tl,Tr              Show devices, libraries or resources\n"
-       L"  b                     Step to previous state capture position\n"
-       L"  M<a/b/s> <val>        Enable or disable audio channels, bitplanes or sprites\n"
-       L"  sp <addr> [<addr2][<size>] Dump sprite information\n"
-       L"  di <mode> [<track>]   Break on disk access. R=DMA read,W=write,RW=both,P=PIO\n"
-       L"                        Also enables level 1 disk logging\n"
-       L"  did <log level>       Enable disk logging\n"
-       L"  dj [<level bitmask>]  Enable joystick/mouse input debugging\n"
+       L"                        Search for string/bytes.\n"
+       L"  T or Tt               Show exec tasks and their PCs.\n"
+       L"  Td,Tl,Tr              Show devices, libraries or resources.\n"
+       L"  b                     Step to previous state capture position.\n"
+       L"  M<a/b/s> <val>        Enable or disable audio channels, bitplanes or sprites.\n"
+       L"  sp <addr> [<addr2][<size>] Dump sprite information.\n"
+       L"  di <mode> [<track>]   Break on disk access. R=DMA read,W=write,RW=both,P=PIO.\n"
+       L"                        Also enables level 1 disk logging.\n"
+       L"  did <log level>       Enable disk logging.\n"
+       L"  dj [<level bitmask>]  Enable joystick/mouse input debugging.\n"
        L"  smc [<0-1>]           Enable self-modifying code detector. 1 = enable break.\n"
-       L"  dm                    Dump current address space map\n"
-       L"  v <vpos> [<hpos>]     Show DMA data (accurate only in cycle-exact mode)\n"
-       L"                        v [-1 to -4] = enable visual DMA debugger\n"
-       L"  ?<value>              Hex/Bin/Dec converter\n"
+       L"  dm                    Dump current address space map.\n"
+       L"  v <vpos> [<hpos>]     Show DMA data (accurate only in cycle-exact mode).\n"
+       L"                        v [-1 to -4] = enable visual DMA debugger.\n"
+       L"  ?<value>              Hex/Bin/Dec converter.\n"
 #ifdef _WIN32
        L"  x                     Close debugger.\n"
        L"  xx                    Switch between console and GUI debugger.\n"
-       L"  mg <address>          Memory dump starting at <address> in GUI\n"
-       L"  dg <address>          Disassembly starting at <address> in GUI\n"
+       L"  mg <address>          Memory dump starting at <address> in GUI.\n"
+       L"  dg <address>          Disassembly starting at <address> in GUI.\n"
 #endif
        L"  q                     Quit the emulator. You don't want to use this command.\n\n"
 };
@@ -324,6 +324,28 @@ static int checkvaltype (TCHAR **c, uae_u32 *val)
        return 0;
 }
 
+static int readsize (int val, TCHAR **c)
+{
+       if ((*c)[0] == '.') {
+               (*c)++;
+               TCHAR cc = _totupper ((*c)[0]);
+               (*c)++;
+               if (cc == 'B')
+                       return 1;
+               if (cc == 'W')
+                       return 2;
+               if (cc == '3')
+                       return 3;
+               if (cc == 'L')
+                       return 4;
+       }
+       if (val > 255 || val < -127)
+               return 2;
+       if (val > 65535 || val < -32767)
+               return 4;
+       return 1;
+}
+
 static uae_u32 readint (TCHAR **c)
 {
        uae_u32 val;
@@ -338,6 +360,18 @@ static uae_u32 readhex (TCHAR **c)
                return val;
        return readhexx (c);
 }
+static uae_u32 readint (TCHAR **c, int *size)
+{
+       uae_u32 val = readint (c);
+       *size = readsize (val, c);
+       return val;
+}
+static uae_u32 readhex (TCHAR **c, int *size)
+{
+       uae_u32 val = readhex (c);
+       *size = readsize (val, c);
+       return val;
+}
 static uae_u32 readbin (TCHAR **c)
 {
        uae_u32 val;
@@ -433,7 +467,7 @@ static uaecptr nextaddr2 (uaecptr addr, int *next)
        uaecptr prev, prevx;
        int size, sizex;
 
-       if (addr >= lastaddr()) {
+       if (addr >= lastaddr ()) {
                *next = -1;
                return 0xffffffff;
        }
@@ -492,10 +526,15 @@ static uaecptr nextaddr2 (uaecptr addr, int *next)
        return addr;
 }
 
-static uaecptr nextaddr (uaecptr addr, uaecptr *end)
+static uaecptr nextaddr (uaecptr addr, uaecptr last, uaecptr *end)
 {
        uaecptr paddr = addr;
        int next;
+       if (last && 0) {
+               if (addr >= last)
+                       return 0xffffffff;
+               return addr + 1;
+       }
        if (addr == 0xffffffff) {
                if (end)
                        *end = currprefs.chipmem_size;
@@ -503,7 +542,7 @@ static uaecptr nextaddr (uaecptr addr, uaecptr *end)
        }
        if (end)
                next = *end;
-       addr = nextaddr2(addr + 1, &next);
+       addr = nextaddr2 (addr + 1, &next);
        if (end)
                *end = next;
 #if 0
@@ -1183,14 +1222,14 @@ static void deepcheatsearch (TCHAR **c)
                (*c)++;
        }
        if (more_params (c))
-               maxdiff = readint(c);
+               maxdiff = readint (c);
 
        if (!memtmp || v == 'S') {
                first = 1;
                xfree (memtmp);
                memsize = 0;
                addr = 0xffffffff;
-               while ((addr = nextaddr (addr, &end)) != 0xffffffff)  {
+               while ((addr = nextaddr (addr, 0, &end)) != 0xffffffff)  {
                        memsize += end - addr;
                        addr = end - 1;
                }
@@ -1201,7 +1240,7 @@ static void deepcheatsearch (TCHAR **c)
                memset (memtmp + memsize, 0xff, memsize2);
                p1 = memtmp;
                addr = 0xffffffff;
-               while ((addr = nextaddr (addr, &end)) != 0xffffffff) {
+               while ((addr = nextaddr (addr, 0, &end)) != 0xffffffff) {
                        for (i = addr; i < end; i++)
                                *p1++ = get_byte (i);
                        addr = end - 1;
@@ -1221,7 +1260,7 @@ static void deepcheatsearch (TCHAR **c)
        addrcnt = 0;
        cnt = 0;
        addr = 0xffffffff;
-       while ((addr = nextaddr (addr, NULL)) != 0xffffffff) {
+       while ((addr = nextaddr (addr, 0, NULL)) != 0xffffffff) {
                uae_s32 b, b2;
                int doremove = 0;
                int addroff = addrcnt >> 3;
@@ -1264,7 +1303,7 @@ static void deepcheatsearch (TCHAR **c)
                } else {
                        p1[addrcnt] = b >> 8;
                        p1[addrcnt + 1] = b >> 0;
-                       addr = nextaddr (addr, NULL);
+                       addr = nextaddr (addr, 0, NULL);
                        if (addr == 0xffffffff)
                                break;
                        addrcnt += 2;
@@ -1277,7 +1316,7 @@ static void deepcheatsearch (TCHAR **c)
                cnt = 0;
                addrcnt = 0;
                addr = 0xffffffff;
-               while ((addr = nextaddr(addr, NULL)) != 0xffffffff) {
+               while ((addr = nextaddr(addr, 0, NULL)) != 0xffffffff) {
                        int addroff = addrcnt >> 3;
                        int addrmask = (size == 1 ? 1 : 3) << (addrcnt & 7);
                        if (p2[addroff] & addrmask)
@@ -1306,7 +1345,7 @@ static void cheatsearch (TCHAR **c)
 
        memsize = 0;
        addr = 0xffffffff;
-       while ((addr = nextaddr (addr, &end)) != 0xffffffff)  {
+       while ((addr = nextaddr (addr, 0, &end)) != 0xffffffff)  {
                memsize += end - addr;
                addr = end - 1;
        }
@@ -1324,22 +1363,10 @@ static void cheatsearch (TCHAR **c)
                vlist = xcalloc (uae_u8, listsize >> 3);
                return;
        }
-       val = readint (c);
-       if (first) {
-               if (val > 255)
-                       size = 2;
-               if (val > 65535)
-                       size = 3;
-               if (val > 16777215)
-                       size = 4;
-       }
-       ignore_ws (c);
-       if (more_params (c))
-               size = readint (c);
-       if (size > 4)
-               size = 4;
-       if (size < 1)
-               size = 1;
+       if (first)
+               val = readint (c, &size);
+       else
+               val = readint (c);
 
        if (vlist == NULL) {
                listsize = memsize;
@@ -1352,7 +1379,7 @@ static void cheatsearch (TCHAR **c)
        clearcheater ();
        addr = 0xffffffff;
        prevmemcnt = memcnt = 0;
-       while ((addr = nextaddr (addr, &end)) != 0xffffffff) {
+       while ((addr = nextaddr (addr, 0, &end)) != 0xffffffff) {
                if (addr + size < end) {
                        for (i = 0; i < size; i++) {
                                int shift = (size - i - 1) * 8;
@@ -1425,7 +1452,7 @@ static void illg_init (void)
                return;
        }
        addr = 0xffffffff;
-       while ((addr = nextaddr (addr, &end)) != 0xffffffff)  {
+       while ((addr = nextaddr (addr, 0, &end)) != 0xffffffff)  {
                if (end < 0x01000000) {
                        memset (illgdebug + addr, c, end - addr);
                } else {
@@ -1663,7 +1690,7 @@ static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp)
                        uae_u32 mask = (1 << (m->size * 8)) - 1;
                        int scnt = size;
                        for (;;) {
-                               if (((m->val & mask) & m->valmask) == ((val & mask) & m->valmask))
+                               if (((m->val & mask) & m->val_mask) == ((val & mask) & m->val_mask))
                                        trigger = 1;
                                if (mask & 0x80000000)
                                        break;
@@ -1701,12 +1728,15 @@ static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp)
                        if (m->val_enabled) {
                                int shift = addr - m->addr;
                                int max = 0;
-                               if (m->val > 256)
+                               if (m->val_size == 2) {
                                        max = 1;
-                               if (m->val > 65536)
+                                       shift = 1 - ((addr - m->addr) & 1);
+                               } else if (m->val_size == 4) {
                                        max = 3;
-                               shift &= max;
+                                       shift = 3 - ((addr - m->addr) & 3);
+                               }
                                *valp = m->val >> ((max - shift) * 8);
+                               return 1;
                        }
                        return 0;
                }
@@ -2001,6 +2031,19 @@ int debug_bankchange (int mode)
        return -1;
 }
 
+static TCHAR *getsizechar (int size)
+{
+       if (size == 4)
+               return L".l";
+       if (size == 3)
+               return L".3";
+       if (size == 2)
+               return L".w";
+       if (size == 1)
+               return L".b";
+       return L"";
+}
+
 void memwatch_dump2 (TCHAR *buf, int bufsize, int num)
 {
        int i;
@@ -2019,7 +2062,7 @@ void memwatch_dump2 (TCHAR *buf, int bufsize, int num)
                        if (mwn->frozen)
                                buf = buf_out (buf, &bufsize, L"F");
                        if (mwn->val_enabled)
-                               buf = buf_out (buf, &bufsize, L" =%X", mwn->val);
+                               buf = buf_out (buf, &bufsize, L" =%X%s", mwn->val, getsizechar (mwn->val_size));
                        if (mwn->modval_written)
                                buf = buf_out (buf, &bufsize, L" =M");
                        if (mwn->mustchange)
@@ -2107,7 +2150,7 @@ static void memwatch (TCHAR **c)
        mwn->size = 1;
        mwn->rwi = 7;
        mwn->val_enabled = 0;
-       mwn->valmask = 0xffffffff;
+       mwn->val_mask = 0xffffffff;
        mwn->frozen = 0;
        mwn->modval_written = 0;
        ignore_ws (c);
@@ -2140,7 +2183,7 @@ static void memwatch (TCHAR **c)
                                } else if (_totupper (**c) == 'C') {
                                        mwn->mustchange = 1;
                                } else {
-                                       mwn->val = readhex (c);
+                                       mwn->val = readhex (c, &mwn->val_size);
                                        mwn->val_enabled = 1;
                                }
                        }
@@ -2161,17 +2204,8 @@ static void writeintomem (TCHAR **c)
        ignore_ws(c);
        addr = readhex (c);
        ignore_ws(c);
-       val = readhex (c);
-       if (val > 0xffff)
-               len = 4;
-       else if (val > 0xff)
-               len = 2;
-       else
-               len = 1;
-       if (more_params (c)) {
-               ignore_ws (c);
-               len = readint (c);
-       }
+       val = readhex (c, &len);
+
        if (len == 4) {
                put_long (addr, val);
                cc = 'L';
@@ -2587,7 +2621,7 @@ static void searchmem (TCHAR **cc)
                        endaddr = readhex (cc);
        }
        console_out_f (L"Searching from %08X to %08X..\n", addr, endaddr);
-       while ((addr = nextaddr (addr, NULL)) != 0xffffffff) {
+       while ((addr = nextaddr (addr, endaddr, NULL)) != 0xffffffff) {
                if (addr == endaddr)
                        break;
                for (i = 0; i < sslen; i++) {
@@ -2852,7 +2886,7 @@ static void disk_debug (TCHAR **inptr)
                        disk_debug_mode |= DISK_DEBUG_PIO;
        }
        if (more_params(inptr))
-               disk_debug_track = readint(inptr);
+               disk_debug_track = readint (inptr);
        if (disk_debug_track < 0 || disk_debug_track > 2 * 83)
                disk_debug_track = -1;
        if (disk_debug_logging == 0)
@@ -2880,7 +2914,7 @@ static void find_ea (TCHAR **inptr)
                        end = readhex (inptr);
        }
        console_out_f (L"Searching from %08X to %08X\n", addr, end);
-       while((addr = nextaddr(addr, &end)) != 0xffffffff) {
+       while((addr = nextaddr(addr, end, &end)) != 0xffffffff) {
                if ((addr & 1) == 0 && addr + 6 <= end) {
                        sea = 0xffffffff;
                        dea = 0xffffffff;
@@ -3037,7 +3071,7 @@ static void debug_1 (void)
                                        inptr++;
                                        inputdevice_logging = 1 | 2;
                                        if (more_params (&inptr))
-                                               inputdevice_logging = readint(&inptr);
+                                               inputdevice_logging = readint (&inptr);
                                        console_out_f (L"Input logging level %d\n", inputdevice_logging);
                                } else if (*inptr == 'm') {
                                        memory_map_dump_2 (0);
index f5616ad41bf9b7df2e7ab2ab848c4d31cf2d40f8..f7adccbabfc7cc9ebcc356b3818a1d340b73bf06 100644 (file)
--- a/disk.cpp
+++ b/disk.cpp
@@ -7,7 +7,7 @@
 * Copyright 1995-2001 Bernd Schmidt
 * Copyright 2000-2003 Toni Wilen
 *
-* High Density Drive Handling by Dr. Adil Temel (C) 2001 [atemel1@hotmail.com]
+* Original High Density Drive Handling by Dr. Adil Temel (C) 2001 [atemel1@hotmail.com]
 *
 */
 
@@ -91,10 +91,6 @@ static uae_u8 writebuffer[544 * MAX_SECTORS];
 #define DSKREADY_TIME 4
 #define DSKREADY_DOWN_TIME 10
 
-#if 0
-#define MAX_DISK_WORDS_PER_LINE 50 /* depends on floppy_speed */
-static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1];
-#endif
 static int dskdmaen, dsklength, dsklength2, dsklen;
 static uae_u16 dskbytr_val;
 static uae_u32 dskpt;
@@ -2886,9 +2882,6 @@ static void disk_doupdate_read (drive * drv, int floppybits)
                bitoffset &= 15;
                floppybits -= drv->trackspeed;
        }
-#if 0
-       dma_tab[j] = 0xffffffff;
-#endif
 }
 
 static void disk_dma_debugmsg (void)
@@ -2897,24 +2890,6 @@ static void disk_dma_debugmsg (void)
                dsklength, dsklength, (adkcon & 0x400) ? dsksync : 0xffff, dskpt, adkcon, M68K_GETPC);
 }
 
-#if 0
-/* disk DMA fetch happens on real Amiga at the beginning of next horizontal line
-(cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd
-data at cycle 0. I don't think any program cares about this small difference.
-*/
-static void dodmafetch (void)
-{
-       int i;
-
-       i = 0;
-       while (dma_tab[i] != 0xffffffff && dskdmaen != 3 && (dmacon & 0x210) == 0x210) {
-               put_word (dskpt, dma_tab[i++]);
-               dskpt += 2;
-       }
-       dma_tab[0] = 0xffffffff;
-}
-#endif
-
 /* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */
 
 uae_u16 DSKBYTR (int hpos)
@@ -3360,9 +3335,6 @@ void DISK_init (void)
 {
        int dr;
 
-#if 0
-       dma_tab[0] = 0xffffffff;
-#endif
        for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
                drive *drv = &floppy[dr];
                /* reset all drive types to 3.5 DD */
index 8aa77b39b26538d922e58103d2fb1de9f2830a2e..8cdbbca21f857882b8a81ba7ae19db8f2101f7ce 100644 (file)
@@ -212,7 +212,7 @@ static int bplres;
 static int plf1pri, plf2pri, bplxor;
 static uae_u32 plf_sprite_mask;
 static int sbasecol[2] = { 16, 16 };
-static int brdsprt, brdblank, brdblank_changed;
+static int brdsprt, brdblank, brdblank_changed, hposendblank;
 
 bool picasso_requested_on;
 bool picasso_on;
@@ -674,12 +674,21 @@ STATIC_INLINE uae_u32 merge_2pixel32 (uae_u32 p1, uae_u32 p2)
        return v;
 }
 
+STATIC_INLINE xcolnr getbgc (void)
+{
+#if 0
+       if (hposendblank)
+               return xcolors[0xf00];
+#endif
+       return (brdblank || hposendblank) ? 0 : colors_for_drawing.acolors[0];
+}
+
 static void fill_line_16 (uae_u8 *buf, unsigned int start, unsigned int stop)
 {
        uae_u16 *b = (uae_u16 *)buf;
        unsigned int i;
        unsigned int rem = 0;
-       xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0];
+       xcolnr col = getbgc ();
        if (((long)&b[start]) & 1)
                b[start++] = (uae_u16) col;
        if (start >= stop)
@@ -700,7 +709,7 @@ static void fill_line_32 (uae_u8 *buf, unsigned int start, unsigned int stop)
 {
        uae_u32 *b = (uae_u32 *)buf;
        unsigned int i;
-       xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0];
+       xcolnr col = getbgc ();
        for (i = start; i < stop; i++)
                b[i] = col;
 }
@@ -714,7 +723,7 @@ static void pfield_do_fill_line (int start, int stop)
        }
 }
 
-STATIC_INLINE void fill_line_2 (int startpos, int len, int blank)
+STATIC_INLINE void fill_line2 (int startpos, int len)
 {
        int shift;
        int nints, nrem;
@@ -731,16 +740,16 @@ STATIC_INLINE void fill_line_2 (int startpos, int len, int blank)
        nrem = nints & 7;
        nints &= ~7;
        start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift));
-       val = blank ? 0 : colors_for_drawing.acolors[0];
+       val = getbgc ();
        for (; nints > 0; nints -= 8, start += 8) {
                *start = val;
-               *(start + 1) = val;
-               *(start + 2) = val;
-               *(start + 3) = val;
-               *(start + 4) = val;
-               *(start + 5) = val;
-               *(start + 6) = val;
-               *(start + 7) = val;
+               *(start+1) = val;
+               *(start+2) = val;
+               *(start+3) = val;
+               *(start+4) = val;
+               *(start+5) = val;
+               *(start+6) = val;
+               *(start+7) = val;
        }
 
        switch (nrem) {
@@ -761,15 +770,14 @@ STATIC_INLINE void fill_line_2 (int startpos, int len, int blank)
        }
 }
 
-STATIC_INLINE void fill_line (void)
+static void fill_line (void)
 {
-       int endpos = visible_left_border + gfxvidinfo.width;
-       int endposh = coord_hw_to_window_x (hsyncstartpos * 2);
-       if (endpos < endposh) {
-               fill_line_2 (visible_left_border, gfxvidinfo.width, brdblank);
+       if (hsyncstartposnative > visible_left_border + gfxvidinfo.width || hposendblank) {
+               fill_line2 (visible_left_border, gfxvidinfo.width);
        } else {
-               fill_line_2 (visible_left_border, endposh - visible_left_border, brdblank);
-               fill_line_2 (endposh, gfxvidinfo.width - endposh, 1);
+               fill_line2 (visible_left_border, hsyncstartposnative);
+               hposendblank = 1;
+               fill_line2 (visible_left_border + hsyncstartposnative, gfxvidinfo.width - hsyncstartposnative);
        }
 }
 
@@ -1849,8 +1857,12 @@ static bool isham (uae_u16 bplcon0)
        return 0;
 }
 
-static void pfield_expand_dp_bplcon2 (int regno, int v)
+static void pfield_expand_dp_bplconx (int regno, int v)
 {
+       if (regno == 0xffff) {
+               hposendblank = 1;
+               return;
+       }
        regno -= 0x1000;
        switch (regno)
        {
@@ -1907,7 +1919,6 @@ STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_fun
        int lastpos = visible_left_border;
        int endpos = visible_left_border + gfxvidinfo.width;
        int diff = 1 << lores_shift;
-       int endposh = coord_hw_to_window_x (hsyncstartpos * 2);
 
        for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) {
                int regno = curr_color_changes[i].regno;
@@ -1926,17 +1937,7 @@ STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_fun
                if (nextpos_in_range > lastpos) {
                        if (lastpos < playfield_start) {
                                int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
-                               if (t == endpos) {
-                                       if (lastpos < endposh)
-                                               (*worker_border) (lastpos, endposh);
-                                       // start of hsync, blank the rest of display
-                                       int blank = brdblank;
-                                       brdblank = 1;
-                                       (*worker_border) (endposh, endpos);
-                                       brdblank = blank;
-                               } else {
-                                       (*worker_border) (lastpos, t);
-                               }
+                               (*worker_border) (lastpos, t);
                                lastpos = t;
                        }
                }
@@ -1948,23 +1949,13 @@ STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_fun
                        }
                }
                if (nextpos_in_range > lastpos) {
-                       if (lastpos >= playfield_end) {
-                               if (nextpos_in_range > endposh) {
-                                       (*worker_border) (lastpos, endposh);
-                                       // start of hsync, blank the rest of display
-                                       int blank = brdblank;
-                                       brdblank = 1;
-                                       (*worker_border) (endposh, nextpos_in_range);
-                                       brdblank = blank;
-                               } else {
-                                       (*worker_border) (lastpos, nextpos_in_range);
-                               }
-                       }
+                       if (lastpos >= playfield_end)
+                               (*worker_border) (lastpos, nextpos_in_range);
                        lastpos = nextpos_in_range;
                }
                if (i != dip_for_drawing->last_color_change) {
                        if (regno >= 0x1000) {
-                               pfield_expand_dp_bplcon2 (regno, value);
+                               pfield_expand_dp_bplconx (regno, value);
                        } else {
                                color_reg_set (&colors_for_drawing, regno, value);
                                colors_for_drawing.acolors[regno] = getxcolor (value);
@@ -1974,7 +1965,6 @@ STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_fun
                        break;
        }
 }
-
 enum double_how {
        dh_buf,
        dh_line,
@@ -2748,22 +2738,24 @@ void finish_drawing_frame (void)
                if (where2 < 0)
                        continue;
 
+               hposendblank = 0;
                pfield_draw_line (line, where2, amiga2aspect_line_map[i1 + 1]);
        }
 
+
        /* clear possible old garbage at the bottom if emulated area become smaller */
        for (i = last_max_ypos; i < gfxvidinfo.height; i++) {
                int i1 = i + min_ypos_for_screen;
                int line = i + thisframe_y_adjust_real;
                int where2 = amiga2aspect_line_map[i1];
-               xcolnr tmp;
 
                if (where2 >= gfxvidinfo.height)
                        break;
                if (where2 < 0)
                        continue;
-               tmp = colors_for_drawing.acolors[0];
-               colors_for_drawing.acolors[0] = getxcolor (0);
+
+               hposendblank = i >= last_max_ypos + 16;
+
                xlinebuffer = gfxvidinfo.linemem;
                if (xlinebuffer == 0)
                        xlinebuffer = row_map[where2];
@@ -2771,7 +2763,6 @@ void finish_drawing_frame (void)
                fill_line ();
                linestate[line] = LINE_UNDECIDED;
                do_flush_line (where2);
-               colors_for_drawing.acolors[0] = tmp;
        }
 
        if (currprefs.leds_on_screen) {
index 7cd2f7643efb2a12149883055ee58c951095d293..7d390e7cbc5748a407d0d1721f95f18276b9d8e9 100644 (file)
 #define        INQ_NODEV       0x1F            /* Unknown or no device */
 #define        INQ_NOTPR       0x1F            /* Logical unit not present (SCSI-1) */
 
+#define MAX_TOC_ENTRIES 103
+struct cd_toc
+{
+       uae_u8 adr, control;
+       uae_u8 tno;
+       uae_u8 point;
+       uae_u8 track;
+       int address; // LSN
+       int paddress; // LSN
+       uae_u8 zero;
+       uae_u8 crc[2];
+};
+struct cd_toc_head
+{
+       int first_track, first_track_offset;
+       int last_track, last_track_offset;
+       int lastaddress; // LSN
+       int tracks;
+       int points;
+       struct cd_toc toc[MAX_TOC_ENTRIES];
+};
+
 #define DEVICE_TYPE_ANY 1
 #define DEVICE_TYPE_SCSI 2
+#define DEVICE_TYPE_IOCTL 3
 #define DEVICE_TYPE_ALLOWEMU   0x10000000
 #define DEVICE_TYPE_CHECKAVAIL 0x20000000
+#define DEVICE_TYPE_USE_OLD    0x40000000
+
+#define SUB_ENTRY_SIZE 12
+#define SUB_CHANNEL_SIZE 96
+#define SUBQ_SIZE (4 + 12)
+
+#define AUDIO_STATUS_NOT_SUPPORTED  0x00
+#define AUDIO_STATUS_IN_PROGRESS    0x11
+#define AUDIO_STATUS_PAUSED         0x12
+#define AUDIO_STATUS_PLAY_COMPLETE  0x13
+#define AUDIO_STATUS_PLAY_ERROR     0x14
+#define AUDIO_STATUS_NO_STATUS      0x15
 
 #define DF_SCSI 0
 #define DF_IOCTL 1
@@ -44,6 +79,7 @@ struct device_info {
     int id;
     TCHAR label[MAX_DPATH];
        TCHAR mediapath[MAX_DPATH];
+       struct cd_toc_head toc;
 };
 
 struct device_scsi_info {
@@ -71,21 +107,23 @@ typedef int (*open_bus_func)(int flags);
 typedef void (*close_bus_func)(void);
 typedef int (*open_device_func)(int);
 typedef void (*close_device_func)(int);
-typedef struct device_info* (*info_device_func)(int, struct device_info*);
+typedef struct device_info* (*info_device_func)(int, struct device_info*, int);
 typedef struct device_scsi_info* (*scsiinfo_func)(int, struct device_scsi_info*);
 typedef uae_u8* (*execscsicmd_out_func)(int, uae_u8*, int);
 typedef uae_u8* (*execscsicmd_in_func)(int, uae_u8*, int, int*);
 typedef int (*execscsicmd_direct_func)(int, struct amigascsi*);
 
+typedef void (*play_subchannel_callback)(uae_u8*, int);
+
 typedef int (*pause_func)(int, int);
 typedef int (*stop_func)(int);
-typedef int (*play_func)(int, uae_u32, uae_u32, int);
+typedef int (*play_func)(int, int, int, int, play_subchannel_callback);
 typedef void (*volume_func)(int, uae_u16);
-typedef uae_u8* (*qcode_func)(int);
-typedef uae_u8* (*toc_func)(int);
-typedef uae_u8* (*read_func)(int, int);
-typedef uae_u8* (*rawread_func)(int, int, int);
-typedef int (*write_func)(int, int);
+typedef int (*qcode_func)(int, uae_u8*, int);
+typedef struct cd_toc_head* (*toc_func)(int);
+typedef uae_u8* (*read_func)(int, uae_u8*, int, int);
+typedef uae_u8* (*rawread_func)(int, uae_u8*, int, int, int);
+typedef int (*write_func)(int, uae_u8*, int, int);
 typedef int (*isatapi_func)(int);
 typedef int (*ismedia_func)(int, int);
 
@@ -126,26 +164,34 @@ extern int sys_command_open (int mode, int unitnum);
 extern void sys_command_close (int mode, int unitnum);
 extern int sys_command_isopen (int unitnum);
 extern void sys_command_setunit (int unitnum);
-extern struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di);
+extern struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di, int);
 extern struct device_scsi_info *sys_command_scsi_info (int mode, int unitnum, struct device_scsi_info *di);
 extern void sys_command_cd_pause (int mode, int unitnum, int paused);
 extern void sys_command_cd_stop (int mode, int unitnum);
-extern int sys_command_cd_play (int mode, int unitnum, uae_u32 startmsf, uae_u32 endmsf, int);
+extern int sys_command_cd_play (int mode, int unitnum, int startlsn, int endlsn, int);
+extern int sys_command_cd_play (int mode, int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc);
 extern void sys_command_cd_volume (int mode, int unitnum, uae_u16 volume);
-extern uae_u8 *sys_command_cd_qcode (int mode, int unitnum);
-extern uae_u8 *sys_command_cd_toc (int mode, int unitnum);
-extern uae_u8 *sys_command_cd_read (int mode, int unitnum, int offset);
-extern uae_u8 *sys_command_cd_rawread (int mode, int unitnum, int offset, int size);
-extern uae_u8 *sys_command_read (int mode, int unitnum, int offset);
-extern int sys_command_write (int mode, int unitnum, int offset);
+extern int sys_command_cd_qcode (int mode, int unitnum, uae_u8*);
+extern struct cd_toc_head *sys_command_cd_toc (int mode, int unitnum);
+extern uae_u8 *sys_command_cd_read (int mode, int unitnum, uae_u8 *data, int block, int size);
+extern uae_u8 *sys_command_cd_rawread (int mode, int unitnum, uae_u8 *data, int sector, int size, int sectorsize);
+extern uae_u8 *sys_command_read (int mode, int unitnum, uae_u8 *data, int block, int size);
+extern int sys_command_write (int mode, int unitnum, uae_u8 *data, int block, int size);
 extern int sys_command_scsi_direct_native(int unitnum, struct amigascsi *as);
 extern int sys_command_scsi_direct (int unitnum, uaecptr request);
 extern int sys_command_ismedia (int mode, int unitnum, int quick);
 
-void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **data, int *datalen, int *parm);
-void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalen, int parm);
+extern void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **data, int *datalen, int *parm);
+extern void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalen, int parm);
+
+extern void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen);
+extern void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen);
 
-void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen);
-void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen);
+extern void cdimage_vsync (void);
 
-extern void cdimage_vsync (void);
\ No newline at end of file
+extern int msf2lsn (int msf);
+extern int lsn2msf (int lsn);
+extern uae_u8 frombcd (uae_u8 v);
+extern uae_u8 tobcd (uae_u8 v);
+extern int fromlongbcd (uae_u8 *p);
+extern void tolongbcd (uae_u8 *p, int v);
\ No newline at end of file
index b632d94a5c34f676f83137713d8e805eae326e2a..c51b21200b63980327adcfcad0e4d961e653009e 100644 (file)
@@ -26,5 +26,7 @@ extern void rethink_cdtv (void);
 extern void cdtv_scsi_int (void);
 extern void cdtv_scsi_clear_int (void);
 
+extern bool cdtv_front_panel (int);
+
 #endif
 
index 61d779416ea200a1a9f00601b01147a432280e95..1fe32c9fd0fea772a69d19f7b0a8a27ec612f4dd 100644 (file)
@@ -110,7 +110,7 @@ extern uae_u16 INTREQR (void);
 
 extern int maxhpos, maxhpos_short;
 extern int maxvpos, maxvpos_nom;
-extern int hsyncstartpos;
+extern int hsyncstartposnative;
 extern int minfirstline, vblank_endline, numscrlines;
 extern int vblank_hz, fake_vblank_hz, vblank_skip, doublescan;
 extern frame_time_t syncbase;
index c9dd6d5947f4d0e0c28ed8500ebb089147694eba..8f49ac7bc36809656852aa83e5b4cb76cd4566ff 100644 (file)
@@ -49,16 +49,16 @@ extern struct breakpoint_node bpnodes[BREAKPOINT_TOTAL];
 
 #define MEMWATCH_TOTAL 8
 struct memwatch_node {
-    uaecptr addr;
-    int size;
-    int rwi;
-    uae_u32 val, valmask;
-    int mustchange;
-    int val_enabled;
-    uae_u32 modval;
-    int modval_written;
-    int frozen;
-    uaecptr pc;
+       uaecptr addr;
+       int size;
+       int rwi;
+       uae_u32 val, val_mask;
+       int val_size, val_enabled;
+       int mustchange;
+       uae_u32 modval;
+       int modval_written;
+       int frozen;
+       uaecptr pc;
 };
 extern struct memwatch_node mwnodes[MEMWATCH_TOTAL];
 
index d61c333b4a75d99abf0941daa792f8b9d89c638f..fd45a90ce888b5b969e2d088924e75dc20dcaf6c 100644 (file)
@@ -158,7 +158,9 @@ enum aks { AKS_ENTERGUI = 0x200, AKS_SCREENSHOT_FILE, AKS_SCREENSHOT_CLIPBOARD,
     AKS_DISKSWAPPER_NEXT,AKS_DISKSWAPPER_PREV,
     AKS_DISKSWAPPER_INSERT0,AKS_DISKSWAPPER_INSERT1,AKS_DISKSWAPPER_INSERT2,AKS_DISKSWAPPER_INSERT3,
        AKS_DISK_PREV0, AKS_DISK_PREV1, AKS_DISK_PREV2, AKS_DISK_PREV3,
-       AKS_DISK_NEXT0, AKS_DISK_NEXT1, AKS_DISK_NEXT2, AKS_DISK_NEXT3
+       AKS_DISK_NEXT0, AKS_DISK_NEXT1, AKS_DISK_NEXT2, AKS_DISK_NEXT3,
+       AKS_CDTV_FRONT_PANEL_STOP, AKS_CDTV_FRONT_PANEL_PLAYPAUSE, AKS_CDTV_FRONT_PANEL_PREV,
+       AKS_CDTV_FRONT_PANEL_NEXT, AKS_CDTV_FRONT_PANEL_REW, AKS_CDTV_FRONT_PANEL_FF
 };
 
 extern int target_checkcapslock (int, int *);
\ No newline at end of file
index 95ced22852699aecc9dc5528e7ab502dcd2f54de..7c106f0e572cbe8fc666b8fb3c380ddbed5a4f71 100644 (file)
@@ -371,6 +371,8 @@ struct uae_prefs {
        int win32_kbledmode;
        TCHAR win32_commandpathstart[MAX_DPATH];
        TCHAR win32_commandpathend[MAX_DPATH];
+       TCHAR win32_parjoyport0[MAX_DPATH];
+       TCHAR win32_parjoyport1[MAX_DPATH];
 
        bool statecapture;
        int statecapturerate, statecapturebuffersize;
index 4433446ee3f7c5c6a6e7e80ed4afc29c3ee7dbce..d60b67f395f6544255403d4ba3143758517349fa 100644 (file)
@@ -97,6 +97,9 @@ extern uae_u8 *restore_cdtv (uae_u8 *src);
 extern uae_u8 *save_cdtv (int *len);
 extern void restore_cdtv_finish (void);
 
+extern uae_u8 *restore_dmac (uae_u8 *src);
+extern uae_u8 *save_dmac (int *len);
+
 extern uae_u8 *restore_filesys (uae_u8 *src);
 extern uae_u8 *save_filesys (int num, int *len);
 extern uae_u8 *restore_filesys_common (uae_u8 *src);
index b76904b6782b5c316aaaf9af929d4d420f124f77..f35bbf5d6699a61fb5f2043b115fb19f8cbe8786 100644 (file)
@@ -12,12 +12,13 @@ uaecptr scsidev_startup (uaecptr resaddr);
 void scsidev_install (void);
 void scsidev_reset (void);
 void scsidev_start_threads (void);
-int scsi_do_disk_change (int device_id, int insert);
+int scsi_do_disk_change (int device_id, int insert, int *pollmode);
 int scsi_do_disk_device_change (void);
 
 extern int log_scsi;
 
 #ifdef _WIN32
+#define UAESCSI_CDEMU 0
 #define UAESCSI_SPTI 1
 #define UAESCSI_SPTISCAN 2
 #define UAESCSI_ASPI_FIRST 3
index 18f7dba44f3843b404a35f6c96b7bb2bdd612211..4b0a4bcabf9baad3d652bd0295d75f8e87d03fb8 100644 (file)
@@ -47,6 +47,7 @@
 #include "autoconf.h"
 #include "rp.h"
 #include "dongle.h"
+#include "cdtv.h"
 
 extern int bootrom_header, bootrom_items;
 
@@ -412,6 +413,7 @@ static struct uae_input_device_kbr_default *keyboard_default;
 #define KBR_DEFAULT_MAP_XA2 7
 #define KBR_DEFAULT_MAP_ARCADIA 8
 #define KBR_DEFAULT_MAP_ARCADIA_XA 9
+#define KBR_DEFAULT_MAP_CDTV 10
 static int **keyboard_default_kbmaps;
 
 static int mouse_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
@@ -2478,6 +2480,15 @@ void inputdevice_add_inputcode (int code, int state)
 
 void inputdevice_do_keyboard (int code, int state)
 {
+       if (code >= 0x72 && code <= 0x77) { // CDTV keys
+               if (cdtv_front_panel (-1)) {
+                       // front panel active
+                       if (!state)
+                               return;
+                       cdtv_front_panel (code - 0x72);
+                       return;
+               }
+       }
        if (code < 0x80) {
                uae_u8 key = code | (state ? 0x00 : 0x80);
                keybuf[key & 0x7f] = (key & 0x80) ? 0 : 1;
@@ -2727,6 +2738,16 @@ void inputdevice_handle_inputcode (void)
        case AKS_DISK_NEXT3:
                disk_prevnext (code - AKS_DISK_NEXT0, 1);
                break;
+#ifdef CDTV
+       case AKS_CDTV_FRONT_PANEL_STOP:
+       case AKS_CDTV_FRONT_PANEL_PLAYPAUSE:
+       case AKS_CDTV_FRONT_PANEL_PREV:
+       case AKS_CDTV_FRONT_PANEL_NEXT:
+       case AKS_CDTV_FRONT_PANEL_REW:
+       case AKS_CDTV_FRONT_PANEL_FF:
+               cdtv_front_panel (code - AKS_CDTV_FRONT_PANEL_STOP);
+       break;
+#endif
        }
 }
 
@@ -3559,6 +3580,11 @@ static int ip_mousecdtv[] =
        INPUTEVENT_JOY1_FIRE_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON,
        -1
 };
+static int ip_mediacdtv[] =
+{
+       INPUTEVENT_KEY_CDTV_PLAYPAUSE, INPUTEVENT_KEY_CDTV_STOP, INPUTEVENT_KEY_CDTV_PREV, INPUTEVENT_KEY_CDTV_NEXT,
+       -1
+};
 static int ip_arcadia[] = {
        INPUTEVENT_SPC_ARCADIA_DIAGNOSTICS, INPUTEVENT_SPC_ARCADIA_PLAYER1, INPUTEVENT_SPC_ARCADIA_PLAYER2,
        INPUTEVENT_SPC_ARCADIA_COIN1, INPUTEVENT_SPC_ARCADIA_COIN2,
@@ -4220,6 +4246,9 @@ static void compatibility_copy (struct uae_prefs *prefs, bool gameports)
                if (JSEM_ISXARCADE1 (i, prefs) || JSEM_ISXARCADE2 (i, prefs))
                        setcompakb (keyboard_default_kbmaps[KBR_DEFAULT_MAP_ARCADIA_XA], ip_arcadiaxa, JSEM_ISXARCADE2 (i, prefs) ? 1 : 0, prefs->jports[i].autofire);
        }
+       if (0 && currprefs.cs_cdtvcd) {
+               setcompakb (keyboard_default_kbmaps[KBR_DEFAULT_MAP_CDTV], ip_mediacdtv, 0, 0);
+       }
 
        // parport
        for (i = 2; i < MAX_JPORTS; i++) {
index be7f1577b7198235107082e6d515f92373dbf72c..e7ae6a7f69b122fdec6612a696e4ef029cdab561 100644 (file)
@@ -363,3 +363,11 @@ DEFEVENT(SPC_ARCADIA_PLAYER1,L"Arcadia player 1",AM_K,0,0,AKS_ARCADIAPLY1)
 DEFEVENT(SPC_ARCADIA_PLAYER2,L"Arcadia player 2",AM_K,0,0,AKS_ARCADIAPLY2)
 DEFEVENT(SPC_ARCADIA_COIN1,L"Arcadia coin player 1",AM_K,0,0,AKS_ARCADIACOIN1)
 DEFEVENT(SPC_ARCADIA_COIN2,L"Arcadia coin player 2",AM_K,0,0,AKS_ARCADIACOIN2)
+
+DEFEVENT(SPC_CDTV_FRONT_PANEL_STOP,L"CDTV Front Panel Stop",AM_K,0,0,AKS_CDTV_FRONT_PANEL_STOP)
+DEFEVENT(SPC_CDTV_FRONT_PANEL_PLAYPAUSE,L"CDTV Front Panel Play/Pause",AM_K,0,0,AKS_CDTV_FRONT_PANEL_PLAYPAUSE)
+DEFEVENT(SPC_CDTV_FRONT_PANEL_PREV,L"CDTV Front Panel Previous",AM_K,0,0,AKS_CDTV_FRONT_PANEL_PREV)
+DEFEVENT(SPC_CDTV_FRONT_PANEL_NEXT,L"CDTV Front Panel Next",AM_K,0,0,AKS_CDTV_FRONT_PANEL_NEXT)
+DEFEVENT(SPC_CDTV_FRONT_PANEL_REW,L"CDTV Front Panel Rewind",AM_K,0,0,AKS_CDTV_FRONT_PANEL_REW)
+DEFEVENT(SPC_CDTV_FRONT_PANEL_FF,L"CDTV Front Panel Fast Forward",AM_K,0,0,AKS_CDTV_FRONT_PANEL_FF)
+
index 1ea097f48f6305e30565706e91f917feac9b9476..d3edb3f3587057944598f80c15199820b0d8bb88 100644 (file)
@@ -42,6 +42,7 @@ int get_next_key (void)
        key = keybuf[kpb_last];
        if (++kpb_last == 256)
                kpb_last = 0;
+       //write_log (L"%02x:%d\n", key >> 1, key & 1);
        return key;
 }
 
index 7d67b3afa7f6496a01e4cd1adc7334ede402a51a..e4899ba0befe0d0b70f5872ffee41dc75d1f4cf6 100644 (file)
@@ -977,7 +977,7 @@ static int execscsicmd_direct (int unitnum, struct amigascsi *as)
        return io_error;
 }
 
-static struct device_info *info_device (int unitnum, struct device_info *di)
+static struct device_info *info_device (int unitnum, struct device_info *di, int quick)
 {
        struct scsi_info *sif = &si[unitnum];
        if (unitnum >= unitcnt)
@@ -1008,7 +1008,7 @@ void win32_aspi_media_change (TCHAR driveletter, int insert)
                        if (now != si[i].mediainserted) {
                                write_log (L"ASPI: media change %c %d\n", driveletter, insert);
                                si[i].mediainserted = now;
-                               scsi_do_disk_change (i + 1, insert);
+                               scsi_do_disk_change (i + 1, insert, NULL);
                        }
                }
        }
index bb24711175106ff3a18f8423d9e48f9696c0429f..52c5364a0f99ce2b2409ea5af13ed154bb306de4 100644 (file)
@@ -3,7 +3,7 @@
 *
 * WIN32 CDROM/HD low level access code (IOCTL)
 *
-* Copyright 2002 Toni Wilen
+* Copyright 2002-2010 Toni Wilen
 *
 */
 
@@ -45,8 +45,6 @@ struct dev_info_ioctl {
        int mediainserted;
        int type;
        int blocksize;
-       int mciid;
-       int cdda;
        CDROM_TOC toc;
        UINT errormode;
        int playend;
@@ -59,7 +57,12 @@ struct dev_info_ioctl {
        uae_u32 cd_last_pos;
        HWAVEOUT cdda_wavehandle;
        int cdda_start, cdda_end;
-       uae_u8 subcode[96 * CDDA_BUFFERS];
+       uae_u8 subcode[SUB_CHANNEL_SIZE * CDDA_BUFFERS];
+       uae_u8 subcodebuf[SUB_CHANNEL_SIZE];
+       bool subcodevalid;
+       play_subchannel_callback cdda_subfunc;
+       struct device_info di;
+       uae_sem_t sub_sem, sub_sem2;
 };
 
 static int MCICDA;
@@ -68,7 +71,7 @@ static struct dev_info_ioctl ciw32[MAX_TOTAL_DEVICES];
 
 static void seterrormode (int unitnum)
 {
-       ciw32[unitnum].errormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+       ciw32[unitnum].errormode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
 }
 static void reseterrormode (int unitnum)
 {
@@ -134,23 +137,6 @@ static int win32_error (int unitnum, const TCHAR *format,...)
        return err;
 }
 
-/* convert minutes, seconds and frames -> logical sector number */
-static int msf2lsn (int        msf)
-{
-       int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff));
-       return sector;
-}
-
-/* convert logical sector number -> minutes, seconds and frames */
-static int lsn2msf (int        sectors)
-{
-       int msf;
-       msf = (sectors / (75 * 60)) << 16;
-       msf |= ((sectors / 75) % 60) << 8;
-       msf |= (sectors % 75) << 0;
-       return msf;
-}
-
 static int close_createfile (int unitnum)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
@@ -168,29 +154,9 @@ static int close_createfile (int unitnum)
        return 0;
 }
 
-static int close_mci (int unitnum)
-{
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-       MCI_GENERIC_PARMS gp = { 0 };
-
-       ciw->playend = -1;
-       if (ciw->mciid > 0) {
-               if (log_scsi)
-                       write_log (L"IOCTL: MCI close\n");
-               mcierr (L"MCI_STOP", mciSendCommand (ciw->mciid, MCI_STOP, MCI_WAIT, (DWORD_PTR)&gp));
-               mcierr (L"MCI_CLOSE", mciSendCommand (ciw->mciid, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp));
-               if (log_scsi)
-                       write_log (L"IOCTL: MCI close completed\n");
-               ciw->mciid = 0;
-               return 1;
-       }
-       return 0;
-}
-
 static int open_createfile (int unitnum, int fullaccess)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
-       int closed = 0;
        int cnt = 50;
        DWORD len;
 
@@ -201,7 +167,6 @@ static int open_createfile (int unitnum, int fullaccess)
                        return 1;
                }
        }
-       closed = close_mci (unitnum);
        if (log_scsi)
                write_log (L"IOCTL: opening IOCTL %s\n", ciw->devname);
        for (;;) {
@@ -220,20 +185,10 @@ static int open_createfile (int unitnum, int fullaccess)
                                }
                        }
                }
-               if (ciw->h == INVALID_HANDLE_VALUE) {
-                       DWORD err = GetLastError ();
-                       if (err == ERROR_SHARING_VIOLATION) {
-                               if (closed && cnt > 0) {
-                                       cnt--;
-                                       Sleep (10);
-                                       continue;
-                               }
-                       }
-                       if (closed)
-                               write_log (L"IOCTL: failed to re-open '%s', err=%d\n", ciw->devname, GetLastError ());
-                       return 0;
-               }
-               break;
+               if (ciw->h != INVALID_HANDLE_VALUE)
+                       break;
+               write_log (L"IOCTL: failed to open '%s', err=%d\n", ciw->devname, GetLastError ());
+               return 0;
        }
        if (!DeviceIoControl (ciw->h, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &len, NULL))
                write_log (L"IOCTL: FSCTL_ALLOW_EXTENDED_DASD_IO returned %d\n", GetLastError ());
@@ -242,40 +197,6 @@ static int open_createfile (int unitnum, int fullaccess)
        return 1;
 }
 
-static int open_mci (int unitnum)
-{
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-       TCHAR elname[10];
-       TCHAR alname[100];
-       MCI_OPEN_PARMS mciOpen;
-       DWORD err, flags;
-       int closed = 0;
-
-       if (ciw->mciid > 0 || MCICDA == 0)
-               return 1;
-       ciw->playend = -1;
-       closed = close_createfile (unitnum);
-       if (log_scsi)
-               write_log (L"IOCTL: MCI opening %s\n", ciw->drvlettername);
-       memset (&mciOpen, 0, sizeof (mciOpen));
-       mciOpen.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO;
-       _stprintf (elname, L"%c:", ciw->drvletter);
-       _stprintf (alname, L"CD%u:", GetCurrentTime ());
-       mciOpen.lpstrElementName = elname;
-       mciOpen.lpstrAlias = alname;
-       flags = MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE | MCI_OPEN_ALIAS | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_WAIT;
-       err = mciSendCommand (0, MCI_OPEN, flags, (DWORD_PTR)(LPVOID)&mciOpen);
-       ciw->mciid = mciOpen.wDeviceID;
-       if (err != MMSYSERR_NOERROR) {
-               if (closed)
-                       mcierr (L"MCI_OPEN", err);
-               return 0;
-       }
-       if (log_scsi)
-               write_log (L"IOCTL: MCI open completed\n");
-       return 1;
-}
-
 static void cdda_closewav (struct dev_info_ioctl *ciw)
 {
        if (ciw->cdda_wavehandle != NULL)
@@ -322,7 +243,7 @@ static void *cdda_play (void *v)
        MMRESULT mmr;
        int volume, volume_main;
        int oldplay;
-
+       int firstloops;
 
        for (i = 0; i < 2; i++) {
                memset (&whdr[i], 0, sizeof (WAVEHDR));
@@ -358,11 +279,6 @@ static void *cdda_play (void *v)
 
                while (ciw->cdda_play > 0) {
 
-                       if (oldplay != ciw->cdda_play) {
-                               cdda_pos = ciw->cdda_start;
-                               oldplay = ciw->cdda_play;
-                       }
-
                        while (!(whdr[bufnum].dwFlags & WHDR_DONE)) {
                                Sleep (10);
                                if (!ciw->cdda_play)
@@ -370,30 +286,62 @@ static void *cdda_play (void *v)
                        }
                        bufon[bufnum] = 0;
 
+                       if (oldplay != ciw->cdda_play) {
+                               cdda_pos = ciw->cdda_start;
+                               oldplay = ciw->cdda_play;
+                               firstloops = 25;
+                               write_log (L"CDDA: playing from %d to %d\n", ciw->cdda_start, ciw->cdda_end);
+                               ciw->subcodevalid = false;
+                       }
+
                        if ((cdda_pos < ciw->cdda_end || ciw->cdda_end == 0xffffffff) && !ciw->cdda_paused && ciw->cdda_play) {
                                RAW_READ_INFO rri;
+                               int sectors = num_sectors;
+
+                               uae_sem_wait (&ciw->sub_sem);
+                               ciw->subcodevalid = false;
+                               memset (ciw->subcode, 0, sizeof ciw->subcode);
+
+                               if (firstloops > 0) {
+
+                                       firstloops--;
+                                       if (ciw->cdda_subfunc)
+                                               ciw->cdda_subfunc (ciw->subcode, sectors);
+                                       memset (px[bufnum], 0, sectors * 2352);
 
-                               seterrormode (unitnum);
-                               rri.DiskOffset.QuadPart = 2048 * (cdda_pos - 150);
-                               rri.SectorCount = num_sectors;
-                               rri.TrackMode = RawWithSubCode;
-                               if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri, px[bufnum], num_sectors * CD_RAW_SECTOR_WITH_SUBCODE_SIZE, &len, NULL)) {
-                                       rri.TrackMode = CDDA;
-                                       if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri, px[bufnum], num_sectors * 2352, &len, NULL)) {
-                                               DWORD err = GetLastError ();
-                                               write_log (L"IOCTL_CDROM_RAW_READ CDDA sector %d returned %d\n", cdda_pos - 150, err);
-                                               //ciw->cdda_play_finished = 1;
-                                               //ciw->cdda_play = -1;
-                                       }
                                } else {
-                                       for (i = 0; i < num_sectors; i++) {
-                                               memcpy (ciw->subcode + i * 96, px[bufnum] + CD_RAW_SECTOR_WITH_SUBCODE_SIZE * i + 2352, 96);
-                                       }
-                                       for (i = 1; i < num_sectors; i++) {
-                                               memmove (px[bufnum] + 2352 * i, px[bufnum] + CD_RAW_SECTOR_WITH_SUBCODE_SIZE * i, 2352);
+
+                                       firstloops = -1;
+                                       seterrormode (unitnum);
+                                       rri.DiskOffset.QuadPart = 2048 * (cdda_pos + 0);
+                                       rri.SectorCount = sectors;
+                                       rri.TrackMode = RawWithSubCode;
+                                       if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri, px[bufnum], sectors * CD_RAW_SECTOR_WITH_SUBCODE_SIZE, &len, NULL)) {
+                                               DWORD err = GetLastError ();
+                                               write_log (L"IOCTL_CDROM_RAW_READ CDDA sector %d returned %d\n", cdda_pos, err);
+                                               if (ciw->cdda_subfunc)
+                                                       ciw->cdda_subfunc (ciw->subcode, sectors);
+                                       } else {
+                                               for (i = 0; i < sectors; i++) {
+                                                       memcpy (ciw->subcode + i * SUB_CHANNEL_SIZE, px[bufnum] + CD_RAW_SECTOR_WITH_SUBCODE_SIZE * i + 2352, SUB_CHANNEL_SIZE);
+                                               }
+                                               if (ciw->cdda_subfunc)
+                                                       ciw->cdda_subfunc (ciw->subcode, sectors); 
+                                               for (i = 1; i < sectors; i++) {
+                                                       memmove (px[bufnum] + 2352 * i, px[bufnum] + CD_RAW_SECTOR_WITH_SUBCODE_SIZE * i, 2352);
+                                               }
+                                               ciw->subcodevalid = true;
                                        }
+                                       reseterrormode (unitnum);
                                }
-                               reseterrormode (unitnum);
+
+                               uae_sem_post (&ciw->sub_sem);
+                               if (ciw->subcodevalid) {
+                                       uae_sem_wait (&ciw->sub_sem2);
+                                       memcpy (ciw->subcodebuf, ciw->subcode + (sectors - 1) * SUB_CHANNEL_SIZE, SUB_CHANNEL_SIZE);
+                                       uae_sem_post (&ciw->sub_sem2);
+                               }
+
 
                                volume = ciw->cdda_volume;
                                volume_main = currprefs.sound_volume;
@@ -415,12 +363,15 @@ static void *cdda_play (void *v)
                                        break;
                                }
 
-                               cdda_pos += num_sectors;
-                               if (cdda_pos - num_sectors < ciw->cdda_end && cdda_pos >= ciw->cdda_end) {
-                                       ciw->cdda_play_finished = 1;
-                                       ciw->cdda_play = -1;
-                                       cdda_pos = ciw->cdda_end;
+                               if (firstloops < 0) {
+                                       cdda_pos += num_sectors;
+                                       if (cdda_pos - num_sectors < ciw->cdda_end && cdda_pos >= ciw->cdda_end) {
+                                               ciw->cdda_play_finished = 1;
+                                               ciw->cdda_play = -1;
+                                               cdda_pos = ciw->cdda_end;
+                                       }
                                }
+
                                ciw->cd_last_pos = cdda_pos;
 
                        }
@@ -439,6 +390,7 @@ static void *cdda_play (void *v)
        }
 
 end:
+       ciw->subcodevalid = false;
        while (!(whdr[0].dwFlags & WHDR_DONE) || !(whdr[1].dwFlags & WHDR_DONE))
                Sleep (10);
        for (i = 0; i < 2; i++)
@@ -463,6 +415,7 @@ static void cdda_stop (int unitnum)
        }
        ciw->cdda_play_finished = 0;
        ciw->cdda_paused = 0;
+       ciw->subcodevalid = 0;
 }
 
 /* pause/unpause CD audio */
@@ -472,37 +425,7 @@ static int ioctl_command_pause (int unitnum, int paused)
 
        if (!unitisopen (unitnum))
                return 0;
-
-       if (ciw->mciid > 0) {
-
-               MCI_GENERIC_PARMS gp = { 0 };
-               if (paused)
-                       mcierr(L"MCI_PAUSE", mciSendCommand (ciw->mciid, MCI_PAUSE, MCI_WAIT, (DWORD_PTR)&gp));
-               else
-                       mcierr(L"MCI_RESUME", mciSendCommand (ciw->mciid, MCI_RESUME, MCI_WAIT, (DWORD_PTR)&gp));
-
-       } else if (ciw->cdda) {
-
-               ciw->cdda_paused = paused;
-               
-       } else {
-
-               DWORD len;
-               int command = paused ? IOCTL_CDROM_PAUSE_AUDIO : IOCTL_CDROM_RESUME_AUDIO;
-               int cnt = 3;
-
-               while (cnt-- > 0) {
-                       seterrormode (unitnum);
-                       if (!DeviceIoControl(ciw32[unitnum].h, command, NULL, 0, NULL, 0, &len, NULL)) {
-                               reseterrormode (unitnum);
-                               if (win32_error (unitnum, paused ? L"IOCTL_CDROM_PAUSE_AUDIO" : L"IOCTL_CDROM_RESUME_AUDIO") < 0)
-                                       continue;
-                               return 0;
-                       }
-                       reseterrormode (unitnum);
-                       break;
-               }
-       }
+       ciw->cdda_paused = paused;
        return 1;
 }
 
@@ -515,33 +438,8 @@ static int ioctl_command_stop (int unitnum)
        if (!unitisopen (unitnum))
                return 0;
 
-       if (ciw->mciid > 0) {
-
-               MCI_GENERIC_PARMS gp = { 0 };
-               mcierr (L"MCI_STOP", mciSendCommand (ciw->mciid, MCI_STOP, MCI_WAIT, (DWORD_PTR)&gp));
-               ciw->playend = -1;
-
-       } else if (ciw->cdda) {
-
-               cdda_stop (unitnum);
+       cdda_stop (unitnum);
                
-       } else {
-
-               DWORD len;
-               int cnt = 3;
-
-               while (cnt-- > 0) {
-                       seterrormode (unitnum);
-                       if(!DeviceIoControl (ciw32[unitnum].h, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &len, NULL)) {
-                               reseterrormode (unitnum);
-                               if (win32_error (unitnum, L"IOCTL_CDROM_STOP_AUDIO") < 0)
-                                       continue;
-                               return 0;
-                       }
-                       reseterrormode (unitnum);
-                       break;
-               }
-       }
        return 1;
 }
 
@@ -553,190 +451,117 @@ static void ioctl_command_volume (int unitnum, uae_u16 volume)
 }
 
 /* play CD audio */
-static int ioctl_command_play (int unitnum, uae_u32 start, uae_u32 end, int scan)
+static int ioctl_command_play (int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
 
        if (!unitisopen (unitnum))
                return 0;
 
-       if (!ciw->cdda)
-               open_mci (unitnum);
-
-       if (ciw->mciid > 0) {
-
-               MCI_SET_PARMS setParms = {0};
-               MCI_PLAY_PARMS playParms = {0};
-
-               setParms.dwTimeFormat = MCI_FORMAT_MSF;
-               mcierr (L"MCI_SET", mciSendCommand (ciw->mciid, MCI_SET, MCI_SET_TIME_FORMAT | MCI_WAIT, (DWORD_PTR)&setParms));
-               playParms.dwFrom = MCI_MAKE_MSF((start >> 16) & 0xff, (start >> 8) & 0xff, start & 0xff);
-               playParms.dwTo = MCI_MAKE_MSF((end >> 16) & 0xff, (end >> 8) & 0xff, end & 0xff);
-               mcierr (L"MCI_PLAY", mciSendCommand (ciw->mciid, MCI_PLAY, MCI_FROM | MCI_TO, (DWORD_PTR)&playParms));
-               ciw->playend = end;
-
-       } else if (ciw->cdda) {
+       if (!open_createfile (unitnum, 0))
+               return 0;
+       ciw->cdda_paused = 0;
+       ciw->cdda_play_finished = 0;
+       ciw->cdda_subfunc = subfunc;
+       if (!ciw->cdda_play) {
+               uae_start_thread (L"cdda_play", cdda_play, ciw, NULL);
+       }
+       ciw->cdda_start = startlsn;
+       ciw->cdda_end = endlsn;
+       ciw->cd_last_pos = ciw->cdda_start;
+       ciw->cdda_play++;
 
-               if (!open_createfile (unitnum, 0))
-                       return 0;
-               ciw->cdda_paused = 0;
-               ciw->cdda_play_finished = 0;
-               if (!ciw->cdda_play) {
-                       uae_start_thread (L"cdda_play", cdda_play, ciw, NULL);
-               }
-               ciw->cdda_start = msf2lsn (start);
-               ciw->cdda_end = msf2lsn (end);
-               ciw->cd_last_pos = ciw->cdda_start;
-               ciw->cdda_play++;
-
-       } else {
-
-               DWORD len;
-               CDROM_PLAY_AUDIO_MSF pa;
-               int cnt = 3;
-
-#if 0
-               {
-                       VOLUME_CONTROL vc;
-                       if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_GET_VOLUME, NULL, 0, &vc, sizeof(vc), &len, NULL))
-                               write_log (L"IOCTL_CDROM_GET_VOLUME %d\n", GetLastError());
-                       vc.PortVolume[0] = 0xff;
-                       vc.PortVolume[1] = 0xff;
-                       vc.PortVolume[2] = 0xff;
-                       vc.PortVolume[3] = 0xff;
-                       if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_SET_VOLUME, &vc, sizeof(vc), NULL, 0, &len, NULL))
-                               write_log (L"IOCTL_CDROM_SET_VOLUME %d\n", GetLastError());
-               }
-#endif
+       return 1;
+}
 
-               while (cnt-- > 0) {
-                       pa.StartingM = start >> 16;
-                       pa.StartingS = start >> 8;
-                       pa.StartingF = start >> 0;
-                       pa.EndingM = end >> 16;
-                       pa.EndingS = end >> 8;
-                       pa.EndingF = end >> 0;
-                       seterrormode (unitnum);
-                       if (!DeviceIoControl (ciw32[unitnum].h, IOCTL_CDROM_PLAY_AUDIO_MSF, &pa, sizeof(pa), NULL, 0, &len, NULL)) {
-                               reseterrormode (unitnum);
-                               if (win32_error (unitnum, L"IOCTL_CDROM_PLAY_AUDIO_MSF %02.%02.%02-%02.%02.%02",
-                                       pa.StartingM, pa.StartingS, pa.StartingF, pa.EndingM, pa.EndingS, pa.EndingF ) < 0) continue;
-                               return 0;
-                       }
-                       reseterrormode (unitnum);
-                       break;
+static void sub_deinterleave (uae_u8 *s, uae_u8 *d)
+{
+       for (int i = 0; i < 8 * 12; i ++) {
+               int dmask = 0x80;
+               int smask = 1 << (7 - (i / 12));
+               (*d) = 0;
+               for (int j = 0; j < 8; j++) {
+                       (*d) |= (s[(i % 12) * 8 + j] & smask) ? dmask : 0;
+                       dmask >>= 1;
                }
+               d++;
        }
-
-       return 1;
 }
 
 /* read qcode */
-static uae_u8 *ioctl_command_qcode (int unitnum)
+static int ioctl_command_qcode (int unitnum, uae_u8 *buf, int sector)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
 
        if (!unitisopen (unitnum)) {
                write_log (L"qcode: %d no unit\n", unitnum);
-               return NULL;
+               return 0;
        }
 
-       if (ciw->mciid > 0) {
+       uae_u8 *p;
+       int trk;
+       CDROM_TOC *toc = &ciw->toc;
+       int pos;
+       int msf;
+       int start, end;
+       int status;
+       bool valid = false;
+       bool regenerate = false;
+
+       memset (buf, 0, SUBQ_SIZE);
+       p = buf;
+
+       status = AUDIO_STATUS_NO_STATUS;
+       if (ciw->cdda_play) {
+               status = AUDIO_STATUS_IN_PROGRESS;
+               if (ciw->cdda_paused)
+                       status = AUDIO_STATUS_PAUSED;
+       } else if (ciw->cdda_play_finished) {
+               status = AUDIO_STATUS_PLAY_COMPLETE;
+       }
 
-               static uae_u8 buf[4 + 12];
-               MCI_STATUS_PARMS mciStatusParms;
-               DWORD err, mode;
-               uae_u8 *p;
-               uae_u32 pos, pos2;
-               int trk;
+       p[1] = status;
+       p[3] = 12;
 
-               memset (buf, 0, sizeof buf);
-               memset (&mciStatusParms, 0, sizeof mciStatusParms);
-               mciStatusParms.dwItem = MCI_STATUS_MODE;
-               err = mciSendCommand (ciw->mciid, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&mciStatusParms);
-               if (err != MMSYSERR_NOERROR)
-                       return 0;
-               mode = mciStatusParms.dwReturn;
-               mciStatusParms.dwItem = MCI_STATUS_CURRENT_TRACK;
-               err = mciSendCommand (ciw->mciid, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&mciStatusParms);
-               if (err != MMSYSERR_NOERROR)
-                       return 0;
-               trk = mciStatusParms.dwReturn - 1;
-               if (trk < 0)
-                       trk = 0;
-               mciStatusParms.dwItem = MCI_STATUS_POSITION;
-               err = mciSendCommand (ciw->mciid, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&mciStatusParms);
-               if (err != MMSYSERR_NOERROR)
-                       return 0;
-               pos = (((mciStatusParms.dwReturn >> 16) & 0xff) << 0) | (((mciStatusParms.dwReturn >> 8) & 0xff) << 8) | (((mciStatusParms.dwReturn >> 0) & 0xff) << 16);
-
-               p = buf;
-               p[1] = AUDIO_STATUS_NO_STATUS;
-               if (mode == MCI_MODE_PLAY)
-                       p[1] = AUDIO_STATUS_IN_PROGRESS;
-               else if (mode == MCI_MODE_PAUSE)
-                       p[1] = AUDIO_STATUS_PAUSED;
-               p[3] = 12;
-
-               p = buf + 4;
-               p[1] = (ciw->toc.TrackData[trk].Control << 0) | (ciw->toc.TrackData[trk].Adr << 4);
-               p[2] = trk + 1;
-               p[3] = 1;
-
-               p[5] = (pos >> 16) & 0xff;
-               p[6] = (pos >> 8) & 0xff;
-               p[7] = (pos >> 0) & 0xff;
-
-               pos = msf2lsn (pos);
-               pos2 = (ciw->toc.TrackData[trk].Address[1] << 16) | (ciw->toc.TrackData[trk].Address[2] << 8) | (ciw->toc.TrackData[trk].Address[3] << 0);
-               pos -= msf2lsn (pos2);
-               if (pos < 0)
-                       pos = 0;
-               pos = lsn2msf (pos);
-
-               p[9] = (pos >> 16) & 0xff;
-               p[10] = (pos >> 8) & 0xff;
-               p[11] = (pos >> 0) & 0xff;
-
-               return buf;
-
-       } else if (ciw->cdda) {
-
-               static uae_u8 buf[4 + 12];
-               uae_u8 *p;
-               int trk;
-               CDROM_TOC *toc = &ciw->toc;
-               int pos;
-               int msf;
-               int start, end;
-               int status;
-
-               memset (buf, 0, sizeof buf);
-               p = buf;
-
-               status = AUDIO_STATUS_NO_STATUS;
-               if (ciw->cdda_play) {
-                       status = AUDIO_STATUS_IN_PROGRESS;
-                       if (ciw->cdda_paused)
-                               status = AUDIO_STATUS_PAUSED;
-               } else if (ciw->cdda_play_finished) {
-                       status = AUDIO_STATUS_PLAY_COMPLETE;
-               }
+       p = buf + 4;
+
+       if (sector < 0)
                pos = ciw->cd_last_pos;
-#if 0
-               pos -= CDDA_BUFFERS * 2;
-               if (ciw->cdda_play && pos < ciw->cdda_start) {
-                       pos = ciw->cdda_start;
-                       status = AUDIO_STATUS_NO_STATUS;
+       else
+               pos = sector;
+
+       if (!regenerate) {
+               if (sector < 0 && ciw->subcodevalid && ciw->cdda_play) {
+                       uae_sem_wait (&ciw->sub_sem2);
+                       uae_u8 subbuf[SUB_CHANNEL_SIZE];
+                       sub_deinterleave (ciw->subcodebuf, subbuf);
+                       memcpy (p, subbuf + 12, 12);
+                       uae_sem_post (&ciw->sub_sem2);
+                       valid = true;
                }
-#endif
-               p[1] = status;
-               p[3] = 12;
-
-               p = buf + 4;
+               if (!valid && sector >= 0) {
+                       DWORD len;
+                       uae_sem_wait (&ciw->sub_sem);
+                       seterrormode (unitnum);
+                       RAW_READ_INFO rri;
+                       rri.DiskOffset.QuadPart = 2048 * (pos + 0);
+                       rri.SectorCount = 1;
+                       rri.TrackMode = RawWithSubCode;
+                       memset (ciw->tempbuffer, 0, CD_RAW_SECTOR_WITH_SUBCODE_SIZE);
+                       if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri, ciw->tempbuffer, CD_RAW_SECTOR_WITH_SUBCODE_SIZE, &len, NULL)) {
+                               DWORD err = GetLastError ();
+                               write_log (L"IOCTL_CDROM_RAW_READ SUBQ CDDA sector %d returned %d\n", pos, err);
+                       }
+                       reseterrormode (unitnum);
+                       uae_u8 subbuf[SUB_CHANNEL_SIZE];
+                       sub_deinterleave (ciw->tempbuffer + 2352, subbuf);
+                       uae_sem_post (&ciw->sub_sem);
+                       memcpy (p, subbuf + 12, 12);
+                       valid = true;
+               }
+       }
 
-               if (pos >= 150)
-                       trk = 0;
+       if (!valid) {
                start = end = 0;
                for (trk = 0; trk <= toc->LastTrack; trk++) {
                        TRACK_DATA *td = &toc->TrackData[trk];
@@ -747,58 +572,19 @@ static uae_u8 *ioctl_command_qcode (int unitnum)
                        if (pos >= start && pos < end)
                                break;
                }
-               p[1] = (toc->TrackData[trk].Control << 0) | (toc->TrackData[trk].Adr << 4);
-               p[2] = trk + 1;
-               p[3] = 1;
+               p[0] = (toc->TrackData[trk].Control << 4) | (toc->TrackData[trk].Adr << 0);
+               p[1] = tobcd (trk + 1);
+               p[2] = tobcd (1);
                msf = lsn2msf (pos);
-               p[5] = (msf >> 16) & 0xff;
-               p[6] = (msf >> 8) & 0xff;
-               p[7] = (msf >> 0) & 0xff;
-               pos -= start;
-               if (pos < 0)
-                       pos = 0;
-               msf = lsn2msf (pos);
-               p[9] = (msf >> 16) & 0xff;
-               p[10] = (msf >> 8) & 0xff;
-               p[11] = (msf >> 0) & 0xff;
-
-               return buf;
-
-       } else {
+               tolongbcd (p + 7, msf);
+               msf = lsn2msf (pos - start - 150);
+               tolongbcd (p + 3, msf);
+       }
 
-               SUB_Q_CHANNEL_DATA qcd;
-               DWORD len;
-               ULONG in = 1;
-               uae_u8 *p = ciw->tempbuffer;
-               int cnt = 3;
+//     write_log (L"%6d %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n",
+//             pos, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]);
+       return 1;
 
-               memset (p, 0, 4 + 12);
-               p[1] = 0x15;
-               p[3] = 12;
-               while (cnt-- > 0) {
-                       reseterrormode (unitnum);
-                       if(!DeviceIoControl (ciw->h, IOCTL_CDROM_READ_Q_CHANNEL, &in, sizeof in, &qcd, sizeof qcd, &len, NULL)) {
-                               reseterrormode (unitnum);
-                               if (win32_error (unitnum, L"IOCTL_CDROM_READ_Q_CHANNEL") < 0)
-                                       continue;
-                               return 0;
-                       }
-                       break;
-               }
-               reseterrormode (unitnum);
-               p[1] = qcd.CurrentPosition.Header.AudioStatus;
-               p += 4;
-               p[1] = (qcd.CurrentPosition.Control << 0) | (qcd.CurrentPosition.ADR << 4);
-               p[2] = qcd.CurrentPosition.TrackNumber;
-               p[3] = qcd.CurrentPosition.IndexNumber;
-               p[5] = qcd.CurrentPosition.AbsoluteAddress[1];
-               p[6] = qcd.CurrentPosition.AbsoluteAddress[2];
-               p[7] = qcd.CurrentPosition.AbsoluteAddress[3];
-               p[9] = qcd.CurrentPosition.TrackRelativeAddress[1];
-               p[10] = qcd.CurrentPosition.TrackRelativeAddress[2];
-               p[11] = qcd.CurrentPosition.TrackRelativeAddress[3];
-               return ciw->tempbuffer;
-       }
 }
 
 typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
@@ -827,7 +613,7 @@ static uae_u8 *spti_read (int unitnum, int sector, int sectorsize)
 
        if (!open_createfile (unitnum, 1))
                return 0;
-       ciw32[unitnum].cd_last_pos = sector + sectorsize;
+       ciw32[unitnum].cd_last_pos = sector;
        cmd[3] = (uae_u8)(sector >> 16);
        cmd[4] = (uae_u8)(sector >> 8);
        cmd[5] = (uae_u8)(sector >> 0);
@@ -858,9 +644,8 @@ static uae_u8 *spti_read (int unitnum, int sector, int sectorsize)
        return p;
 }
 
-uae_u8 *ioctl_command_rawread (int unitnum, int sector, int sectorsize)
+uae_u8 *ioctl_command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize)
 {
-       int cnt = 3;
        RAW_READ_INFO rri;
        DWORD len;
        uae_u8 *p = ciw32[unitnum].tempbuffer;
@@ -874,7 +659,7 @@ uae_u8 *ioctl_command_rawread (int unitnum, int sector, int sectorsize)
        cdda_stop (unitnum);
        if (sectorsize != 2336 && sectorsize != 2352 && sectorsize != 2048)
                return 0;
-       while (cnt-- > 0) {
+       while (size-- > 0) {
                gui_flicker_led (LED_CD, unitnum, 1);
                seterrormode (unitnum);
                rri.DiskOffset.QuadPart = sector * 2048;
@@ -888,7 +673,11 @@ uae_u8 *ioctl_command_rawread (int unitnum, int sector, int sectorsize)
                                write_log (L"IOCTL rawread unit=%d sector=%d blocksize=%d, ERR=%d\n", unitnum, sector, sectorsize, err);
                }
                reseterrormode (unitnum);
-               ciw32[unitnum].cd_last_pos = sector + sectorsize;
+               if (data) {
+                       memcpy (data, p, sectorsize);
+                       data += sectorsize;
+               }
+               ciw32[unitnum].cd_last_pos = sector;
                break;
        }
        if (sectorsize == 2352)
@@ -896,7 +685,7 @@ uae_u8 *ioctl_command_rawread (int unitnum, int sector, int sectorsize)
        return p + 16;
 }
 
-static int ioctl_command_readwrite (int unitnum, int sector, int write, int blocksize, uae_u8 **ptr)
+static int ioctl_command_readwrite (int unitnum, int sector, int size, int write, int blocksize, uae_u8 *data, uae_u8 **ptr)
 {
        DWORD dtotal;
        int cnt = 3;
@@ -910,6 +699,7 @@ static int ioctl_command_readwrite (int unitnum, int sector, int write, int bloc
        if (!open_createfile (unitnum, 0))
                return 0;
        cdda_stop (unitnum);
+       ciw32[unitnum].cd_last_pos = sector;
        while (cnt-- > 0) {
                gui_flicker_led (LED_CD, unitnum, 1);
                seterrormode (unitnum);
@@ -922,11 +712,14 @@ static int ioctl_command_readwrite (int unitnum, int sector, int write, int bloc
                reseterrormode (unitnum);
                break;
        }
-       cnt = 3;
-       while (cnt-- > 0) {
+       while (size-- > 0) {
                gui_flicker_led (LED_CD, unitnum, 1);
                seterrormode (unitnum);
                if (write) {
+                       if (data) {
+                               memcpy (p, data, blocksize);
+                               data += blocksize;
+                       }
                        if (!WriteFile (ciw32[unitnum].h, p, blocksize, &dtotal, 0)) {
                                int err;
                                reseterrormode (unitnum);
@@ -937,6 +730,7 @@ static int ioctl_command_readwrite (int unitnum, int sector, int write, int bloc
                                        return -1;
                                return 0;
                        }
+                       *ptr = p;
                } else {
                        dtotal = 0;
                        if (!ReadFile (ciw32[unitnum].h, p, blocksize, &dtotal, 0)) {
@@ -951,41 +745,30 @@ static int ioctl_command_readwrite (int unitnum, int sector, int write, int bloc
                                if (log_scsi)
                                        write_log (L"IOCTL unit %d, sector %d: ReadFile()==0. SPTI=%d\n", unitnum, sector, *ptr == 0 ? GetLastError () : 0);
                                return 1;
-#if 0
-                               DWORD len = CD_RAW_SECTOR_WITH_SUBCODE_SIZE, err = -1;
-                               RAW_READ_INFO rri = { 0 };
-                               rri.DiskOffset.QuadPart = sector * 2048;
-                               rri.SectorCount = 1;
-                               rri.TrackMode = RawWithSubCode;
-                               memset (p, 0, blocksize);
-                               if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri,
-                                       p, len, &len, NULL)) {
-                                               err = GetLastError (); /* returns ERROR_IO_DEVICE and still succeeds?! */
-                               }
-                               p += 16; /* skip raw header */
-                               write_log (L"ioctl_command_read(%d,%d)==0, IOCTL_CDROM_RAW_READ = d\n",
-                                       sector, blocksize, err);
-#endif
+                       } else {
+                               *ptr = p;
+                       }
+                       if (data) {
+                               memcpy (data, p, blocksize);
+                               data += blocksize;
                        }
                }
                reseterrormode (unitnum);
                gui_flicker_led (LED_CD, unitnum, 1);
-               break;
        }
-       *ptr = p;
        return 1;
 }
 
-static int ioctl_command_write (int unitnum, int sector)
+static int ioctl_command_write (int unitnum, uae_u8 *data, int sector, int size)
 {
        uae_u8 *ptr;
-       return ioctl_command_readwrite (unitnum, sector, 1, ciw32[unitnum].blocksize, &ptr);
+       return ioctl_command_readwrite (unitnum, sector, size, 1, ciw32[unitnum].blocksize, data, &ptr);
 }
 
-static uae_u8 *ioctl_command_read (int unitnum, int sector)
+static uae_u8 *ioctl_command_read (int unitnum, uae_u8 *data, int sector, int size)
 {
        uae_u8 *ptr;
-       if (ioctl_command_readwrite (unitnum, sector, 0, ciw32[unitnum].blocksize, &ptr) > 0)
+       if (ioctl_command_readwrite (unitnum, sector, size, 0, ciw32[unitnum].blocksize, data, &ptr) > 0)
                return ptr;
        return NULL;
 }
@@ -998,17 +781,19 @@ static int fetch_geometry (int unitnum, struct device_info *di)
 
        if (!open_createfile (unitnum, 0))
                return 0;
+       uae_sem_wait (&ciw32[unitnum].sub_sem);
+       seterrormode (unitnum);
        while (cnt-- > 0) {
-               seterrormode (unitnum);
-               if (!DeviceIoControl (ciw32[unitnum].h, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof(geom), &len, NULL)) {
-                       reseterrormode (unitnum);
+               if (!DeviceIoControl (ciw32[unitnum].h, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof (geom), &len, NULL)) {
                        if (win32_error (unitnum, L"IOCTL_CDROM_GET_DRIVE_GEOMETRY") < 0)
                                continue;
+                       reseterrormode (unitnum);
+                       uae_sem_post (&ciw32[unitnum].sub_sem);
                        return 0;
                }
-               reseterrormode (unitnum);
-               break;
        }
+       reseterrormode (unitnum);
+       uae_sem_post (&ciw32[unitnum].sub_sem);
        if (di) {
                di->cylinders = geom.Cylinders.LowPart;
                di->sectorspertrack = geom.SectorsPerTrack;
@@ -1021,37 +806,17 @@ static int fetch_geometry (int unitnum, struct device_info *di)
 static int ismedia (int unitnum)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
-       if (ciw->mciid > 0) {
-
-               DWORD err;
-               MCI_STATUS_PARMS mciStatusParms;
-
-               memset (&mciStatusParms, 0, sizeof mciStatusParms);
-               mciStatusParms.dwItem = MCI_STATUS_MEDIA_PRESENT;
-               err = mciSendCommand (ciw->mciid, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&mciStatusParms);
-               if (err != MMSYSERR_NOERROR)
-                       return 0;
-               if (mciStatusParms.dwReturn)
-                       return 1;
-               return 0;
-
-       } else {
-
-               struct device_info di;
-               memset (&di, 0, sizeof di);
-               return fetch_geometry (unitnum, &di);
-
-       }
+       return fetch_geometry (unitnum, &ciw->di);
 }
 
 /* read toc */
-static uae_u8 *ioctl_command_toc (int unitnum)
+static struct cd_toc_head *ioctl_command_toc (int unitnum)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
        DWORD len;
        int i;
-       uae_u8 *p = ciw->tempbuffer;
+       struct cd_toc_head *th = (struct cd_toc_head*)ciw->tempbuffer;
+       struct cd_toc *t = th->toc;
        int cnt = 3;
        CDROM_TOC *toc = &ciw->toc;
 
@@ -1075,44 +840,64 @@ static uae_u8 *ioctl_command_toc (int unitnum)
                break;
        }
 
-       p[0] = ((toc->LastTrack + 4) * 11) >> 8;
-       p[1] = ((toc->LastTrack + 4) * 11) & 0xff;
-       p[2] = 1;
-       p[3] = toc->LastTrack;
-       p += 4;
-       memset (p, 0, 11);
-       p[0] = 1;
-       p[1] = (toc->TrackData[0].Control << 0) | (toc->TrackData[0].Adr << 4);
-       p[3] = 0xa0;
-       p[8] = 1;
-       p += 11;
-       memset (p, 0, 11);
-       p[0] = 1;
-       p[1] = 0x10;
-       p[3] = 0xa1;
-       p[8] = toc->LastTrack;
-       p += 11;
-       memset (p, 0, 11);
-       p[0] = 1;
-       p[1] = 0x10;
-       p[3] = 0xa2;
-       p[8] = toc->TrackData[toc->LastTrack].Address[1];
-       p[9] = toc->TrackData[toc->LastTrack].Address[2];
-       p[10] = toc->TrackData[toc->LastTrack].Address[3];
-       p += 11;
+       memset (th, 0, sizeof (struct cd_toc_head));
+       th->first_track = toc->FirstTrack;
+       th->last_track = toc->LastTrack;
+       th->tracks = th->last_track - th->first_track + 1;
+       th->points = th->tracks + 3;
+       th->lastaddress = msf2lsn ((toc->TrackData[toc->LastTrack].Address[1] << 16) | (toc->TrackData[toc->LastTrack].Address[2] << 8) |
+               (toc->TrackData[toc->LastTrack].Address[3] << 0));
+
+       t->adr = 1;
+       t->point = 0xa0;
+       t->track = th->first_track;
+       t++;
+
+       th->first_track_offset = 1;
        for (i = 0; i < toc->LastTrack; i++) {
-               memset (p, 0, 11);
-               p[0] = 1;
-               p[1] = (toc->TrackData[i].Control << 0) | (toc->TrackData[i].Adr << 4);
-               p[2] = 0;
-               p[3] = i + 1;
-               p[8] = toc->TrackData[i].Address[1];
-               p[9] = toc->TrackData[i].Address[2];
-               p[10] = toc->TrackData[i].Address[3];
-               p += 11;
+               t->adr = toc->TrackData[i].Adr;
+               t->control = toc->TrackData[i].Control;
+               t->paddress = msf2lsn ((toc->TrackData[i].Address[1] << 16) | (toc->TrackData[i].Address[2] << 8) |
+                       (toc->TrackData[i].Address[3] << 0));
+               t->point = t->track = i + 1;
+               t++;
        }
+
+       th->last_track_offset = toc->LastTrack;
+       t->adr = 1;
+       t->point = 0xa1;
+       t->track = th->last_track;
+       t++;
+
+       t->adr = 1;
+       t->point = 0xa2;
+       t->paddress = th->lastaddress;
+       t++;
+
        gui_flicker_led (LED_CD, unitnum, 1);
-       return ciw32[unitnum].tempbuffer;
+       return th;
+}
+
+static void update_device_info (int unitnum)
+{
+       if (!unitcheck (unitnum))
+               return;
+       struct device_info *di = &ciw32[unitnum].di;
+       di->bus = unitnum;
+       di->target = 0;
+       di->lun = 0;
+       di->media_inserted = 0;
+       di->bytespersector = 2048;
+       _stprintf (di->mediapath, L"\\\\.\\%c:", ciw32[unitnum].drvletter);
+       if (fetch_geometry (unitnum, di)) { // || ioctl_command_toc (unitnum))
+               di->media_inserted = 1;
+               ciw32[unitnum].blocksize = di->bytespersector;
+       }
+       di->write_protected = ciw32[unitnum].type == DRIVE_CDROM ? 1 : 0;
+       di->type = ciw32[unitnum].type == DRIVE_CDROM ? INQ_ROMD : INQ_DASD;
+       di->id = ciw32[unitnum].drvletter;
+       _tcscpy (di->label, ciw32[unitnum].drvlettername);
+       memcpy (&di->toc, &ciw32[unitnum].toc, sizeof (struct cd_toc_head));
 }
 
 /* open device level access to cd rom drive */
@@ -1120,7 +905,6 @@ static int sys_cddev_open (int unitnum)
 {
        struct dev_info_ioctl *ciw = &ciw32[unitnum];
 
-       ciw->cdda = 1;
        ciw->cdda_volume = 0xffff;
        ciw->cdda_volume_main = currprefs.sound_volume;
        /* buffer must be page aligned for device access */
@@ -1133,7 +917,10 @@ static int sys_cddev_open (int unitnum)
                write_log (L"IOCTL: failed to open '%s', err=%d\n", ciw->devname, GetLastError ());
                goto error;
        }
+       uae_sem_init (&ciw->sub_sem, 0, 1);
+       uae_sem_init (&ciw->sub_sem2, 0, 1);
        ciw->mediainserted = ioctl_command_toc (unitnum) ? 1 : 0;
+       update_device_info (unitnum);
        write_log (L"IOCTL: device '%s' opened succesfully (unit number=%d,media=%d)\n", ciw->devname, unitnum, ciw->mediainserted);
        ioctl_command_stop (unitnum);
        return 0;
@@ -1155,9 +942,10 @@ void sys_cddev_close (int unitnum)
                return;
        cdda_stop (unitnum);
        close_createfile (unitnum);
-       close_mci (unitnum);
        VirtualFree (ciw->tempbuffer, 0, MEM_RELEASE);
        ciw->tempbuffer = NULL;
+       uae_sem_destroy (&ciw->sub_sem);
+       uae_sem_destroy (&ciw->sub_sem2);
 }
 
 static int open_device (int unitnum)
@@ -1233,27 +1021,17 @@ static int ioctl_ismedia (int unitnum, int quick)
                struct dev_info_ioctl *ciw = &ciw32[unitnum];
                return ciw->mediainserted;
        }
+       update_device_info (unitnum);
        return ismedia (unitnum);
 }
 
-static struct device_info *info_device (int unitnum, struct device_info *di)
+static struct device_info *info_device (int unitnum, struct device_info *di, int quick)
 {
        if (!unitcheck (unitnum))
                return 0;
-       di->bus = unitnum;
-       di->target = 0;
-       di->lun = 0;
-       di->media_inserted = 0;
-       di->bytespersector = 2048;
-       _stprintf (di->mediapath, L"\\\\.\\%c:", ciw32[unitnum].drvletter);
-       if (fetch_geometry (unitnum, di)) { // || ioctl_command_toc (unitnum))
-               di->media_inserted = 1;
-               ciw32[unitnum].blocksize = di->bytespersector;
-       }
-       di->write_protected = ciw32[unitnum].type == DRIVE_CDROM ? 1 : 0;
-       di->type = ciw32[unitnum].type == DRIVE_CDROM ? INQ_ROMD : INQ_DASD;
-       di->id = ciw32[unitnum].drvletter;
-       _tcscpy (di->label, ciw32[unitnum].drvlettername);
+       if (!quick)
+               update_device_info (unitnum);
+       memcpy (di, &ciw32[unitnum].di, sizeof (struct device_info));
        return di;
 }
 
@@ -1265,7 +1043,8 @@ void win32_ioctl_media_change (TCHAR driveletter, int insert)
                if (ciw32[i].drvletter == driveletter && ciw32[i].mediainserted != insert) {
                        write_log (L"IOCTL: media change %s %d\n", ciw32[i].drvlettername, insert);
                        ciw32[i].mediainserted = insert;
-                       scsi_do_disk_change (driveletter, insert);
+                       update_device_info (i);
+                       scsi_do_disk_change (driveletter, insert, NULL);
 #ifdef RETROPLATFORM
                        rp_cd_image_change (i, ciw32[i].drvlettername);
 #endif
index be6832d62d247b0e6376f3962d61c737d2578289..e06a8813ac29ce06e385f1c2bfaaef160332f71d 100644 (file)
@@ -3,7 +3,7 @@
 *
 * WIN32 CDROM/HD low level access code (SPTI)
 *
-* Copyright 2002-2005 Toni Wilen
+* Copyright 2002-2010 Toni Wilen
 *
 */
 
@@ -514,7 +514,7 @@ static int getid (int unitnum)
        return dev_info[unitnum].drvletter ? dev_info[unitnum].drvletter : unitnum + 1;
 }
 
-static struct device_info *info_device (int unitnum, struct device_info *di)
+static struct device_info *info_device (int unitnum, struct device_info *di, int quick)
 {
        struct dev_info_spti *dispti;
        if (unitnum >= MAX_TOTAL_DEVICES || dev_info[unitnum].handle == INVALID_HANDLE_VALUE)
@@ -547,7 +547,7 @@ void win32_spti_media_change (TCHAR driveletter, int insert)
                        if (now != dev_info[i].mediainserted) {
                                write_log (L"SPTI: media change %c %d\n", dev_info[i].drvletter, insert);
                                dev_info[i].mediainserted = now;
-                               scsi_do_disk_change (getid (i), insert);
+                               scsi_do_disk_change (getid (i), insert, NULL);
 #ifdef RETROPLATFORM
                                rp_cd_image_change (i, dev_info[i].drvletter ? dev_info[i].drvlettername : dev_info[i].name);
 #endif
index bd09f2d78704cc95a241a0127a8c210ca24a1ff2..7cbe44a86f9e4727435fe068f977a880053a17be 100644 (file)
@@ -38,6 +38,7 @@
 #ifdef WINDDK
 #include <winioctl.h>
 #include <ntddkbd.h>
+#include <ntddpar.h>
 #endif
 #include <setupapi.h>
 #include <devguid.h>
@@ -57,6 +58,7 @@
 #define DIDC_RAW 2
 #define DIDC_WIN 3
 #define DIDC_CAT 4
+#define DIDC_PARJOY 5
 
 struct didata {
        int type;
@@ -77,6 +79,9 @@ struct didata {
        int catweasel;
        int coop;
 
+       HANDLE parjoy;
+       PAR_QUERY_INFORMATION oldparjoystatus;
+
        int axles;
        int buttons, buttons_real;
        int axismappings[MAX_MAPPINGS];
@@ -91,6 +96,8 @@ struct didata {
        int axisparentdir[MAX_MAPPINGS];
 };
 
+#define MAX_PARJOYPORTS 2
+
 #define DI_BUFFER 30
 #define DI_KBBUFFER 50
 
@@ -550,6 +557,53 @@ static int initialize_tablet (void)
 #endif
 }
 
+#if 0
+static int initialize_parjoyport (void)
+{
+       for (int i = 0; i < MAX_PARJOYPORTS && num_joystick < MAX_INPUT_DEVICES; i++) {
+               struct didata *did;
+               TCHAR *p = i ? currprefs.win32_parjoyport1 : currprefs.win32_parjoyport0;
+               if (p[0] == 0)
+                       continue;
+               HANDLE ph = CreateFile (p, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+               if (ph == INVALID_HANDLE_VALUE) {
+                       write_log (L"PARJOY: '%s' failed to open: %u\n", p, GetLastError ());
+                       continue;
+               }
+               write_log (L"PARJOY: '%s' open\n", p);
+               for (int j = 0; j < 2; j++) {
+                       TCHAR tmp[100];
+                       did = di_joystick;
+                       did += num_joystick;
+                       cleardid(did);
+                       did->connection = DIDC_PARJOY;
+                       did->parjoy = ph;
+                       _stprintf (tmp, L"Parallel joystick %d.%d", i + 1, j + 1);
+                       did->name = my_strdup (tmp);
+                       did->sortname = my_strdup (tmp);
+                       _stprintf (tmp, L"PARJOY%d.%d", i, j);
+                       did->configname = my_strdup (tmp);
+                       did->buttons = did->buttons_real = 1;
+                       did->axles = 2;
+                       did->axissort[0] = 0;
+                       did->axisname[0] = my_strdup (L"X-Axis");
+                       did->axissort[1] = 1;
+                       did->axisname[1] = my_strdup (L"Y-Axis");
+                       for (j = 0; j < did->buttons; j++) {
+                               did->buttonsort[j] = j;
+                               _stprintf (tmp, L"Button %d", j + 1);
+                               did->buttonname[j] = my_strdup (tmp);
+                       }
+                       did->priority = -1;
+                       fixbuttons (did);
+                       fixthings (did);
+                       num_joystick++;
+               }
+       }
+       return 0;
+}
+#endif
+
 static int initialize_catweasel (void)
 {
        int j, i;
@@ -595,7 +649,7 @@ static int initialize_catweasel (void)
                        did->sortname = my_strdup (tmp);
                        _stprintf (tmp, L"CWJOY%d", i);
                        did->configname = my_strdup (tmp);
-                       did->buttons = did->buttons_real =(catweasel_isjoystick() & 0x80) ? 3 : 1;
+                       did->buttons = did->buttons_real = (catweasel_isjoystick () & 0x80) ? 3 : 1;
                        did->axles = 2;
                        did->axissort[0] = 0;
                        did->axisname[0] = my_strdup (L"X-Axis");
@@ -757,6 +811,29 @@ static void getvidpid (const TCHAR *devname, int *vid, int *pid, int *mi)
        getvidpid2 (devname, mi, L"MI_");
 }
 
+static void addrkblabels (struct didata *did)
+{
+       int j = 0;
+       for (int k = 0; k < 254; k++) {
+               TCHAR tmp[100];
+               tmp[0] = 0;
+               if (rawkeyboardlabels[j] != NULL) {
+                       if (rawkeyboardlabels[j][0]) {
+                               _tcscpy (tmp, rawkeyboardlabels[j]);
+                               j++;
+                       }
+               } else {
+                       j++;
+               }
+               if (!tmp[0])
+                       _stprintf (tmp, L"KEY_%02X", k + 1);
+               did->buttonname[k] = my_strdup (tmp);
+               did->buttonmappings[k] = k + 1;
+               did->buttonsort[k] = k + 1;
+               did->buttons++;
+       }
+}
+
 static int initialize_rawinput (void)
 {
        RAWINPUTDEVICELIST *ridl = 0;
@@ -833,7 +910,7 @@ static int initialize_rawinput (void)
                                        continue;
                                if (rnum_kb < 2)
                                        continue;
-                               if (num_keyboard >= MAX_INPUT_DEVICES - 1)
+                               if (num_keyboard >= MAX_INPUT_DEVICES)
                                        continue;
                                did += num_keyboard;
                                num_keyboard++;
@@ -896,34 +973,28 @@ static int initialize_rawinput (void)
                                }
                                did->priority = -1;
                        } else {
-                               int j;
                                PRID_DEVICE_INFO_KEYBOARD rdik = &rdi->keyboard;
                                write_log (L"type=%d sub=%d mode=%d fkeys=%d indicators=%d tkeys=%d\n",
                                        rdik->dwType, rdik->dwSubType, rdik->dwKeyboardMode,
                                        rdik->dwNumberOfFunctionKeys, rdik->dwNumberOfIndicators, rdik->dwNumberOfKeysTotal);
-                               j = 0;
-                               for (int k = 0; k < 254; k++) {
-                                       TCHAR tmp[100];
-                                       tmp[0] = 0;
-                                       if (rawkeyboardlabels[j] != NULL) {
-                                               if (rawkeyboardlabels[j][0]) {
-                                                       _tcscpy (tmp, rawkeyboardlabels[j]);
-                                                       j++;
-                                               }
-                                       } else {
-                                               j++;
-                                       }
-                                       if (!tmp[0])
-                                               _stprintf (tmp, L"KEY_%02X", k + 1);
-                                       did->buttonname[k] = my_strdup (tmp);
-                                       did->buttonmappings[k] = k + 1;
-                                       did->buttonsort[k] = k + 1;
-                                       did->buttons++;
-                               }
+                               addrkblabels (did);
                        }
                }
        }
 
+       if (rnum_kb     && num_keyboard < MAX_INPUT_DEVICES - 1) {
+               struct didata *did = di_keyboard + num_keyboard;
+               num_keyboard++;
+               rkb++;
+               did->name = my_strdup (L"WinUAE null keyboard");
+               did->rawinput = NULL;
+               did->connection = DIDC_RAW;
+               did->sortname = my_strdup (L"NULLKEYBOARD");
+               did->priority = -2;
+               did->configname = my_strdup (L"NULLKEYBOARD");
+               addrkblabels (did);
+       }
+
        rawinputfriendlynames ();
 
        xfree (ridl);
@@ -997,10 +1068,11 @@ static void handle_rawinput_2 (RAWINPUT *raw)
 
        if (raw->header.dwType == RIM_TYPEMOUSE) {
                PRAWMOUSE rm = &raw->data.mouse;
+               HANDLE h = raw->header.hDevice;
 
                for (num = 0; num < num_mouse; num++) {
                        did = &di_mouse[num];
-                       if (did->rawinput == raw->header.hDevice)
+                       if (did->rawinput == h)
                                break;
                }
 #ifdef DI_DEBUG_RAWINPUT
@@ -1082,6 +1154,7 @@ static void handle_rawinput_2 (RAWINPUT *raw)
 
        } else if (raw->header.dwType == RIM_TYPEKEYBOARD) {
                PRAWKEYBOARD rk = &raw->data.keyboard;
+               HANDLE h = raw->header.hDevice;
                int scancode = rk->MakeCode & 0x7f;
                int pressed = (rk->Flags & RI_KEY_BREAK) ? 0 : 1;
 
@@ -1098,17 +1171,29 @@ static void handle_rawinput_2 (RAWINPUT *raw)
                // eat E1 extended keys
                if (rk->Flags & (RI_KEY_E1))
                        return;
+               if (scancode == 0) {
+                       scancode = MapVirtualKey (rk->VKey, MAPVK_VK_TO_VSC);
+#ifdef DI_DEBUG_RAWINPUT
+                       write_log (L"VK->CODE: %x\n", scancode);
+#endif
+               }
                if (rk->VKey == 0xff || (rk->Flags & RI_KEY_E0))
                        scancode |= 0x80;
                if (rk->MakeCode == KEYBOARD_OVERRUN_MAKE_CODE)
                        return;
-               if (scancode == 0xaa)
+               if (scancode == 0xaa || scancode == 0)
                        return;
 
                for (num = 0; num < num_keyboard; num++) {
                        did = &di_keyboard[num];
-                       if (did->acquired && did->rawinput == raw->header.hDevice)
-                               break;
+                       if (did->connection != DIDC_RAW)
+                               continue;
+                       if (did->acquired) {
+                               if (did->rawinput == h)
+                                       break;
+                               if (h == NULL && num_keyboard == 1)
+                                       break;
+                       }
                }
                if (num == num_keyboard) {
                        if (!istest && scancode == DIK_F12 && pressed && isfocus ())
@@ -1484,10 +1569,13 @@ static void di_dev_free (struct didata *did)
 {
        if (did->lpdi)
                IDirectInputDevice8_Release (did->lpdi);
+       if (did->parjoy != INVALID_HANDLE_VALUE)
+               CloseHandle (did->parjoy);
        xfree (did->name);
        xfree (did->sortname);
        xfree (did->configname);
        memset (did, 0, sizeof (struct didata));
+       did->parjoy = INVALID_HANDLE_VALUE;
 }
 
 static int di_do_init (void)
@@ -1534,6 +1622,8 @@ static int di_do_init (void)
        initialize_windowsmouse ();
        write_log (L"Catweasel joymouse initialization..\n");
        initialize_catweasel ();
+//     write_log (L"Parallel joystick port initialization..\n");
+//     initialize_parjoyport ();
        write_log (L"wintab tablet initialization..\n");
        initialize_tablet ();
        write_log (L"end\n");
@@ -2397,6 +2487,19 @@ static void read_joystick (void)
                                }
                        }
                        continue;
+               } else if (did->connection == DIDC_PARJOY) {
+                       DWORD ret;
+                       PAR_QUERY_INFORMATION inf;
+                       ret = 0;
+                       if (DeviceIoControl (did->parjoy, IOCTL_PAR_QUERY_INFORMATION, NULL, 0, &inf, sizeof inf, &ret, NULL)) {
+                               write_log (L"PARJOY: IOCTL_PAR_QUERY_INFORMATION = %u\n", GetLastError ());
+                       } else {
+                               if (inf.Status != did->oldparjoystatus.Status) {
+                                       write_log (L"PARJOY: %08x\n", inf.Status);
+                                       did->oldparjoystatus.Status = inf.Status;
+                               }
+                       }
+                       continue;
                }
                lpdi = did->lpdi;
                if (!lpdi || did->connection != DIDC_DX)
index 1f560756d90ccd4ecd0d01ee8efcf40f75f8d84c..be2c8e65e8751bdc7d598b6e767b797d66754f2e 100644 (file)
@@ -246,7 +246,6 @@ struct my_openfile_s *my_open (const TCHAR *name, int flags)
        DWORD CreationDisposition = OPEN_EXISTING;
        DWORD FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
        DWORD attr;
-       wstring fname;
 
        mos = xmalloc (struct my_openfile_s, 1);
        if (!mos)
@@ -267,9 +266,7 @@ struct my_openfile_s *my_open (const TCHAR *name, int flags)
        if (CreationDisposition == CREATE_ALWAYS && attr != INVALID_FILE_ATTRIBUTES &&
                (attr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))
                SetFileAttributes (name, FILE_ATTRIBUTE_NORMAL);
-       fname = L"\\\\?\\";
-       fname += name;
-       h = CreateFile (fname.c_str(), DesiredAccess, ShareMode, NULL, CreationDisposition, FlagsAndAttributes, NULL);
+       h = CreateFile (name, DesiredAccess, ShareMode, NULL, CreationDisposition, FlagsAndAttributes, NULL);
        if (h == INVALID_HANDLE_VALUE) {
                DWORD err = GetLastError();
                if (err == ERROR_ACCESS_DENIED && (DesiredAccess & GENERIC_WRITE)) {
index cd85b75bd852b9266728c8b1ee0584720f102d7c..be2282cee277ee1c26e3f69309a84571fba1842a 100644 (file)
@@ -185,12 +185,14 @@ static int kb_cd32_np[] = { DIK_NUMPAD4, -1, DIK_NUMPAD6, -1, DIK_NUMPAD8, -1, D
 static int kb_cd32_ck[] = { DIK_LEFT, -1, DIK_RIGHT, -1, DIK_UP, -1, DIK_DOWN, -1, DIK_RCONTROL, -1, DIK_RMENU, -1, DIK_NUMPAD7, -1, DIK_NUMPAD9, -1, DIK_DIVIDE, -1, DIK_SUBTRACT, -1, DIK_MULTIPLY, -1, -1 };
 static int kb_cd32_se[] = { DIK_A, -1, DIK_D, -1, DIK_W, -1, DIK_S, -1, -1, DIK_LMENU, -1, DIK_LSHIFT, -1, DIK_NUMPAD7, -1, DIK_NUMPAD9, -1, DIK_DIVIDE, -1, DIK_SUBTRACT, -1, DIK_MULTIPLY, -1, -1 };
 
+static int kb_cdtv[] = { DIK_NUMPAD1, -1, DIK_NUMPAD3, -1, DIK_NUMPAD7, -1, DIK_NUMPAD9, -1, -1 };
+
 static int kb_xa1[] = { DIK_NUMPAD4, -1, DIK_NUMPAD6, -1, DIK_NUMPAD8, -1, DIK_NUMPAD2, DIK_NUMPAD5, -1, DIK_LCONTROL, -1, DIK_LMENU, -1, DIK_SPACE, -1, -1 };
 static int kb_xa2[] = { DIK_D, -1, DIK_G, -1, DIK_R, -1, DIK_F, -1, DIK_A, -1, DIK_S, -1, DIK_Q, -1 };
 static int kb_arcadia[] = { DIK_F2, -1, DIK_1, -1, DIK_2, -1, DIK_5, -1, DIK_6, -1, -1 };
 static int kb_arcadiaxa[] = { DIK_1, -1, DIK_2, -1, DIK_3, -1, DIK_4, -1, DIK_6, -1, DIK_LBRACKET, DIK_LSHIFT, -1, DIK_RBRACKET, -1, DIK_C, -1, DIK_5, -1, DIK_Z, -1, DIK_X, -1, -1 };
 
-static int *kbmaps[] = { kb_np, kb_ck, kb_se, kb_cd32_np, kb_cd32_ck, kb_cd32_se, kb_xa1, kb_xa2, kb_arcadia, kb_arcadiaxa };
+static int *kbmaps[] = { kb_np, kb_ck, kb_se, kb_cd32_np, kb_cd32_ck, kb_cd32_se, kb_xa1, kb_xa2, kb_arcadia, kb_arcadiaxa, kb_cdtv };
 
 extern int ispressed (int key);
 
index fb9efe6907a72872fd65ae31404655048179aeb8..799efbb06af3bd626513394d26473ceb4fcf4a9e 100644 (file)
@@ -25,6 +25,7 @@
 #include <io.h>
 
 #include <setupapi.h>
+#include <Ntddpar.h>
 
 #include "sysdeps.h"
 #include "options.h"
@@ -1197,7 +1198,10 @@ void hsyncstuff (void)
 #endif
 }
 
-static int enumserialports_2 (int cnt)
+const static GUID GUID_DEVINTERFACE_PARALLEL = {0x97F76EF0,0xF883,0x11D0,
+{0xAF,0x1F,0x00,0x00,0xF8,0x00,0x84,0x5C}};
+
+static int enumports_2 (struct serparportinfo *pi, int cnt, bool parport)
 {
        // Create a device information set that will be the container for
        // the device interfaces.
@@ -1208,7 +1212,7 @@ static int enumserialports_2 (int cnt)
        DWORD dwDetDataSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA) + 256 * sizeof (TCHAR);
        DWORD ii;
 
-       hDevInfo = SetupDiGetClassDevs (&GUID_CLASS_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+       hDevInfo = SetupDiGetClassDevs (parport ? &GUID_DEVINTERFACE_PARALLEL : &GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if(hDevInfo == INVALID_HANDLE_VALUE)
                return 0;
        // Enumerate the serial ports
@@ -1218,7 +1222,7 @@ static int enumserialports_2 (int cnt)
        ifcData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
        pDetData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
        for (ii = 0; bOk; ii++) {
-               bOk = SetupDiEnumDeviceInterfaces (hDevInfo, NULL, &GUID_CLASS_COMPORT, ii, &ifcData);
+               bOk = SetupDiEnumDeviceInterfaces (hDevInfo, NULL, parport ? &GUID_DEVINTERFACE_PARALLEL : &GUID_DEVINTERFACE_COMPORT, ii, &ifcData);
                if (bOk) {
                        // Got a device. Get the details.
                        SP_DEVINFO_DATA devdata = { sizeof (SP_DEVINFO_DATA)};
@@ -1234,21 +1238,21 @@ static int enumserialports_2 (int cnt)
                                bSuccess = bSuccess && SetupDiGetDeviceRegistryProperty (
                                        hDevInfo, &devdata, SPDRP_DEVICEDESC, NULL,
                                        (PBYTE)desc, sizeof (desc), NULL);
-                               if (bSuccess && cnt < MAX_SERIAL_PORTS) {
+                               if (bSuccess && cnt < MAX_SERPAR_PORTS) {
                                        TCHAR *p;
-                                       comports[cnt].dev = my_strdup (pDetData->DevicePath);
-                                       comports[cnt].name = my_strdup (fname);
-                                       p = _tcsstr (fname, L"(COM");
+                                       pi[cnt].dev = my_strdup (pDetData->DevicePath);
+                                       pi[cnt].name = my_strdup (fname);
+                                       p = _tcsstr (fname, parport ? L"(LPT" : L"(COM");
                                        if (p && (p[5] == ')' || p[6] == ')')) {
-                                               comports[cnt].cfgname = xmalloc (TCHAR, 100);
+                                               pi[cnt].cfgname = xmalloc (TCHAR, 100);
                                                if (isdigit(p[5]))
-                                                       _stprintf (comports[cnt].cfgname, L"COM%c%c", p[4], p[5]);
+                                                       _stprintf (pi[cnt].cfgname, parport ? L"LPT%c%c" : L"COM%c%c", p[4], p[5]);
                                                else
-                                                       _stprintf (comports[cnt].cfgname, L"COM%c", p[4]);
+                                                       _stprintf (pi[cnt].cfgname, parport ? L"LPT%c" : L"COM%c", p[4]);
                                        } else {
-                                               comports[cnt].cfgname = my_strdup (pDetData->DevicePath);
+                                               pi[cnt].cfgname = my_strdup (pDetData->DevicePath);
                                        }
-                                       write_log (L"SERPORT: '%s' = '%s' = '%s'\n", comports[cnt].name, comports[cnt].cfgname, comports[cnt].dev);
+                                       write_log (L"%s: '%s' = '%s' = '%s'\n", parport ? L"PARPORT" : L"SERPORT", pi[cnt].name, pi[cnt].cfgname, pi[cnt].dev);
                                        cnt++;
                                }
                        } else {
@@ -1270,6 +1274,8 @@ end:
        return cnt;
 }
 
+static struct serparportinfo parports[MAX_SERPAR_PORTS];
+
 int enumserialports (void)
 {
        int cnt, i, j;
@@ -1291,7 +1297,7 @@ int enumserialports (void)
        cnt++;
 #endif
 
-       cnt = enumserialports_2 (cnt);
+       cnt = enumports_2 (comports, cnt, false);
        for (i = 0; i < 10; i++) {
                _stprintf (name, L"COM%d", i);
                if (!QueryDosDevice (name, devname, sizeof devname / sizeof (TCHAR)))
@@ -1301,7 +1307,7 @@ int enumserialports (void)
                                break;
                }
                if (j == cnt) {
-                       if (cnt >= MAX_SERIAL_PORTS)
+                       if (cnt >= MAX_SERPAR_PORTS)
                                break;
                        comports[j].dev = xmalloc (TCHAR, 100);
                        _stprintf (comports[cnt].dev, L"\\.\\\\%s", name);
@@ -1311,7 +1317,9 @@ int enumserialports (void)
                        cnt++;
                }
        }
-       write_log (L"Serial port enumeration end\n");
+       write_log (L"Parallel port enumeration..\n");
+       enumports_2 (parports, 0, true);
+       write_log (L"Port enumeration end\n");
        return cnt;
 }
 
@@ -1319,7 +1327,7 @@ void sernametodev (TCHAR *sername)
 {
        int i;
 
-       for (i = 0; i < MAX_SERIAL_PORTS && comports[i].name; i++) {
+       for (i = 0; i < MAX_SERPAR_PORTS && comports[i].name; i++) {
                if (!_tcscmp(sername, comports[i].cfgname)) {
                        _tcscpy (sername, comports[i].dev);
                        return;
@@ -1331,7 +1339,7 @@ void sernametodev (TCHAR *sername)
 void serdevtoname (TCHAR *sername)
 {
        int i;
-       for (i = 0; i < MAX_SERIAL_PORTS && comports[i].name; i++) {
+       for (i = 0; i < MAX_SERPAR_PORTS && comports[i].name; i++) {
                if (!_tcscmp(sername, comports[i].dev)) {
                        _tcscpy (sername, comports[i].cfgname);
                        return;
index 5cae6d2e3db0b3adf11af12a5c158035514332d6..cc6f56b7f215a0fdd460e0da2474c13b19f7ee30 100644 (file)
@@ -33,22 +33,23 @@ void serialuartbreak (int);
 extern void unload_ghostscript (void);
 extern int load_ghostscript (void);
 
-#define MAX_SERIAL_PORTS 32
-struct serialportinfo
+#define MAX_SERPAR_PORTS 32
+struct serparportinfo
 {
     TCHAR *dev;
     TCHAR *cfgname;
     TCHAR *name;
 };
-extern struct serialportinfo comports[MAX_SERIAL_PORTS];
+extern struct serparportinfo comports[MAX_SERPAR_PORTS];
+extern struct serparportinfo parports[MAX_SERPAR_PORTS];
 
 extern int enumserialports (void);
 extern void sernametodev (TCHAR*);
 extern void serdevtoname (TCHAR*);
 
-extern void epson_printchar(uae_u8 c);
-extern int epson_init(const TCHAR *printername, int pins);
-extern void epson_close(void);
+extern void epson_printchar (uae_u8 c);
+extern int epson_init (const TCHAR *printername, int pins);
+extern void epson_close (void);
 
 #define PARALLEL_MATRIX_TEXT 1
 #define PARALLEL_MATRIX_EPSON 2
index 15ab712616b367569b2f8dcf6fb2886e5565c2df..f85fbfb7caef45a73db822874a01e24eede5bd4d 100644 (file)
 #define IDC_INFOBOX_TEXT2               1802
 #define IDC_INFOBOX_TEXT1               1803
 #define IDC_INFOBOX_TEXT3               1804
+#define IDC_CD_EJECT                    1804
+#define IDC_CD_TEXT                     1805
+#define IDC_CD_TYPE                     1806
+#define IDC_CD_SELECT                   1807
 #define ID__FLOPPYDRIVES                40004
 #define ID_FLOPPYDRIVES_DF0             40005
 #define ID_ST_CONFIGURATION             40010
 #define _APS_3D_CONTROLS                     1
 #define _APS_NEXT_RESOURCE_VALUE        356
 #define _APS_NEXT_COMMAND_VALUE         40045
-#define _APS_NEXT_CONTROL_VALUE         1803
+#define _APS_NEXT_CONTROL_VALUE         1808
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
index bcda23355ae3040ed9b1e0e0e4b84b91d115bd0a..2f2b7896ea40e0c766285d30d062e38f9b6c1fca 100644 (file)
@@ -282,25 +282,30 @@ BEGIN
     CONTROL         "DF3:",IDC_DF3ENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,3,111,34,15\r
 END\r
 \r
-IDD_HARDDISK DIALOGEX 0, 0, 300, 237\r
+IDD_HARDDISK DIALOGEX 0, 0, 300, 243\r
 STYLE DS_LOCALEDIT | DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD\r
 EXSTYLE WS_EX_CONTEXTHELP\r
 FONT 8, "MS Sans Serif", 0, 0, 0x1\r
 BEGIN\r
-    CONTROL         "List1",IDC_VOLUMELIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,0,290,167\r
-    PUSHBUTTON      "Add &Directory or Archive...",IDC_NEW_FS,10,171,103,15\r
-    PUSHBUTTON      "Add &Hardfile...",IDC_NEW_HF,130,171,74,15\r
-    PUSHBUTTON      "Add Ha&rd Drive...",IDC_NEW_HD,220,171,75,15\r
-    PUSHBUTTON      "Remove",IDC_REMOVE,235,193,60,15\r
-    PUSHBUTTON      "&Properties",IDC_EDIT,235,210,60,15\r
-    CONTROL         "Add PC drives at startup",IDC_MAPDRIVES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,192,100,10\r
-    CONTROL         "Disable UAEFSDB-support",IDC_NOUAEFSDB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,192,119,10\r
-    CONTROL         "Don't use Windows Recycle Bin",IDC_NORECYCLEBIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,203,121,10\r
-    CONTROL         "Include network drives..",IDC_MAPDRIVES_NET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,226,101,10\r
-    CONTROL         "Include CD/DVD drives..",IDC_MAPDRIVES_CD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,215,100,10\r
-    CONTROL         "Automount removable drives",IDC_MAPDRIVES_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,215,115,10\r
+    CONTROL         "List1",IDC_VOLUMELIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,0,290,130\r
+    PUSHBUTTON      "Add &Directory or Archive...",IDC_NEW_FS,10,135,103,15\r
+    PUSHBUTTON      "Add &Hardfile...",IDC_NEW_HF,130,135,74,15\r
+    PUSHBUTTON      "Add Ha&rd Drive...",IDC_NEW_HD,220,135,75,15\r
+    PUSHBUTTON      "Remove",IDC_REMOVE,235,155,60,15\r
+    PUSHBUTTON      "&Properties",IDC_EDIT,235,172,60,15\r
+    CONTROL         "Add PC drives at startup",IDC_MAPDRIVES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,154,100,10\r
+    CONTROL         "Disable UAEFSDB-support",IDC_NOUAEFSDB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,154,119,10\r
+    CONTROL         "Don't use Windows Recycle Bin",IDC_NORECYCLEBIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,165,121,10\r
+    CONTROL         "Include network drives..",IDC_MAPDRIVES_NET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,188,101,10\r
+    CONTROL         "Include CD/DVD drives..",IDC_MAPDRIVES_CD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,177,100,10\r
+    CONTROL         "Automount removable drives",IDC_MAPDRIVES_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,177,115,10\r
     CONTROL         "Include removable drives..",IDC_MAPDRIVES_REMOVABLE,\r
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,203,100,10\r
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,165,100,10\r
+    COMBOBOX        IDC_CD_TEXT,5,224,289,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP\r
+    PUSHBUTTON      "Eject",IDC_CD_EJECT,265,204,30,15\r
+    PUSHBUTTON      "Select image file",IDC_CD_SELECT,90,204,98,15\r
+    COMBOBOX        IDC_CD_TYPE,194,205,63,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\r
+    LTEXT           "CD drive/image",IDC_STATIC,5,206,70,10,SS_CENTERIMAGE\r
 END\r
 \r
 IDD_SOUND DIALOGEX 0, 0, 300, 237\r
@@ -1200,6 +1205,10 @@ BEGIN
     BEGIN\r
     END\r
 \r
+    IDD_HARDDISK, DIALOG\r
+    BEGIN\r
+    END\r
+\r
     IDD_SOUND, DIALOG\r
     BEGIN\r
     END\r
@@ -1224,6 +1233,10 @@ BEGIN
     BEGIN\r
     END\r
 \r
+    IDD_HARDFILE, DIALOG\r
+    BEGIN\r
+    END\r
+\r
     IDD_CHIPSET, DIALOG\r
     BEGIN\r
     END\r
@@ -1237,6 +1250,10 @@ BEGIN
         BOTTOMMARGIN, 237\r
     END\r
 \r
+    IDD_HARDDRIVE, DIALOG\r
+    BEGIN\r
+    END\r
+\r
     IDD_MISC2, DIALOG\r
     BEGIN\r
     END\r
@@ -1269,6 +1286,10 @@ BEGIN
     BEGIN\r
     END\r
 \r
+    IDD_EXPANSION, DIALOG\r
+    BEGIN\r
+    END\r
+\r
     IDD_INPUTMAP, DIALOG\r
     BEGIN\r
         TOPMARGIN, 1\r
@@ -1418,7 +1439,7 @@ BEGIN
     IDS_NETDISCONNECTED     "Cable disconnected"\r
     IDS_QS_CD               "CD"\r
     IDS_QS_CD_AUTO          "Autodetect"\r
-    IDS_QS_CD_IMAGE         "Image file"\r
+    IDS_QS_CD_IMAGE         "Image mode"\r
     IDS_REMAPTITLE          "Input captured. F12 = Exit. F11 = Skip current event in Remap mode."\r
     IDS_FILTER_NOOVERLAYS   "No overlays available"\r
 END\r
index 8257dd56f778450b7f1b7fc0da6ce8e7b557d5f0..9c5aa3bb52dcc97af82ff0a8691143c28e0ec3bf 100644 (file)
@@ -844,7 +844,7 @@ void rp_fixup_options (struct uae_prefs *p)
                for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
                        if ((1 << i) & cd_mask) {
                                struct device_info di = { 0 };
-                               if (sys_command_info (DF_IOCTL, i, &di))
+                               if (sys_command_info (DF_IOCTL, i, &di, 0))
                                        rp_cd_image_change (i, di.mediapath);
                        }
                }
index 84927a8473970c0fa5b410fbff55c967d5b28dfb..acef1a91fb2e053b53e548584083692371f6d34c 100644 (file)
@@ -2533,7 +2533,7 @@ void target_default_options (struct uae_prefs *p, int type)
        }
 }
 
-static const TCHAR *scsimode[] = { L"none", L"SPTI", L"SPTI+SCSISCAN", L"AdaptecASPI", L"NeroASPI", L"FrogASPI", 0 };
+static const TCHAR *scsimode[] = { L"SCSIEMU", L"SPTI", L"SPTI+SCSISCAN", L"AdaptecASPI", L"NeroASPI", L"FrogASPI", 0 };
 
 void target_save_options (struct zfile *f, struct uae_prefs *p)
 {
@@ -2594,6 +2594,8 @@ void target_save_options (struct zfile *f, struct uae_prefs *p)
        cfgfile_target_dwrite_bool (f, L"powersavedisabled", p->win32_powersavedisabled);
        cfgfile_target_dwrite_str (f, L"exec_before", p->win32_commandpathstart);
        cfgfile_target_dwrite_str (f, L"exec_after", p->win32_commandpathend);
+       cfgfile_target_dwrite_str (f, L"parjoyport0", p->win32_parjoyport0);
+       cfgfile_target_dwrite_str (f, L"parjoyport1", p->win32_parjoyport1);
 
 }
 
@@ -2660,6 +2662,8 @@ int target_parse_option (struct uae_prefs *p, TCHAR *option, TCHAR *value)
                || cfgfile_yesno (option, value, L"powersavedisabled", &p->win32_powersavedisabled)
                || cfgfile_string (option, value, L"exec_before", p->win32_commandpathstart, sizeof p->win32_commandpathstart / sizeof (TCHAR))
                || cfgfile_string (option, value, L"exec_after", p->win32_commandpathend, sizeof p->win32_commandpathend / sizeof (TCHAR))
+               || cfgfile_string (option, value, L"parjoyport0", p->win32_parjoyport0, sizeof p->win32_parjoyport0 / sizeof (TCHAR))
+               || cfgfile_string (option, value, L"parjoyport1", p->win32_parjoyport1, sizeof p->win32_parjoyport1 / sizeof (TCHAR))
                || cfgfile_intval (option, value, L"specialkey", &p->win32_specialkey, 1)
                || cfgfile_intval (option, value, L"guikey", &p->win32_guikey, 1)
                || cfgfile_intval (option, value, L"kbledmode", &p->win32_kbledmode, 1)
index 620bebd64ce1e9e77c67b1b430067a1846adc8fe..360b149d652afc4d235f1133a40f6c4d508114c7 100644 (file)
@@ -18,8 +18,8 @@
 #define WINUAEPUBLICBETA 1
 #define LANG_DLL 1
 
-#define WINUAEBETA L"2"
-#define WINUAEDATE MAKEBD(2010, 7, 8)
+#define WINUAEBETA L"3"
+#define WINUAEDATE MAKEBD(2010, 7, 16)
 #define WINUAEEXTRA L""
 #define WINUAEREV L""
 
index 03ff29e5ce003b8f90dc620db1855243b42292ea..9d29c0588590466ea6514e335d430638a9d2f365 100644 (file)
@@ -95,7 +95,7 @@
 #define USS_FORMAT_STRING_SAVE L"(*.uss)\0*.uss\0"
 #define HDF_FORMAT_STRING L"(*.hdf;*.vhd;*.rdf;*.hdz;*.rdz)\0*.hdf;*.vhd;*.rdf;*.hdz;*.rdz\0"
 #define INP_FORMAT_STRING L"(*.inp)\0*.inp\0"
-#define  CD_FORMAT_STRING L"(*.cue;*.iso)\0*.cue;*.iso;" ARCHIVE_STRING L"\0"
+#define  CD_FORMAT_STRING L"(*.cue;*.ccd;*.iso)\0*.cue;*.ccd;*.iso;" ARCHIVE_STRING L"\0"
 #define CONFIG_HOST L"Host"
 #define CONFIG_HARDWARE L"Hardware"
 
@@ -151,6 +151,9 @@ static TCHAR quickstart_cddrive[16];
 static int quickstart_ok, quickstart_ok_floppy;
 static void addfloppytype (HWND hDlg, int n);
 static void addfloppyhistory (HWND hDlg);
+static void addfloppyhistory_2 (HWND hDlg, int n, int f_text, int type);
+static void addcdtype (HWND hDlg, int id);
+static void getfloppyname (HWND hDlg, int n, int cd, int f_text);
 
 static int C_PAGES;
 #define MAX_C_PAGES 30
@@ -1917,20 +1920,48 @@ static UINT_PTR CALLBACK ofnhook (HWND hDlg, UINT message, WPARAM wParam, LPARAM
        return FALSE;
 }
 
-static void selectdisk (struct uae_prefs *prefs, HWND hDlg, int num, int id, TCHAR *full_path)
+static void eject_cd (void)
 {
-       SetDlgItemText (hDlg, id, full_path);
-       if (iscd (num)) {
-               if (quickstart_cddrive[0]) {
-                       quickstart_cdtype = 0;
-                       quickstart_cddrive[0] = 0;
+       workprefs.cdimagefile[0] = 0;
+       quickstart_cddrive[0] = 0;
+       workprefs.cdimagefileuse = false;
+       if (full_property_sheet) {
+               quickstart_cdtype = 0;
+       } else {
+               if (quickstart_cdtype > 0) {
+                       quickstart_cdtype = 1;
+                       workprefs.cdimagefileuse = true;
                }
-               _tcscpy (prefs->cdimagefile, full_path);
-               DISK_history_add (full_path, -1, HISTORY_CD, 0);
+       }
+}
+
+static void ejectfloppy (int n)
+{
+       if (iscd (n)) {
+               eject_cd ();
        } else {
-               _tcscpy(prefs->df[num], full_path);
-               DISK_history_add (full_path, -1, HISTORY_FLOPPY, 0);
+               workprefs.df[n][0] = 0;
+       }
+}
+
+static void selectcd (struct uae_prefs *prefs, HWND hDlg, int num, int id, TCHAR *full_path)
+{
+       SetDlgItemText (hDlg, id, full_path);
+       if (quickstart_cddrive[0])
+               eject_cd ();
+       _tcscpy (prefs->cdimagefile, full_path);
+       DISK_history_add (full_path, -1, HISTORY_CD, 0);
+}
+
+static void selectdisk (struct uae_prefs *prefs, HWND hDlg, int num, int id, TCHAR *full_path)
+{
+       if (iscd (num)) {
+               selectcd (prefs, hDlg, num, id, full_path);
+               return;
        }
+       SetDlgItemText (hDlg, id, full_path);
+       _tcscpy(prefs->df[num], full_path);
+       DISK_history_add (full_path, -1, HISTORY_FLOPPY, 0);
 }
 
 
@@ -2249,6 +2280,9 @@ int DiskSelection_2 (HWND hDlg, WPARAM wParam, int flag, struct uae_prefs *prefs
                        }
                        SetDlgItemText (hDlg, wParam, full_path);
                        break;
+               case IDC_CD_SELECT:
+                       selectcd (prefs, hDlg, 0, IDC_CD_TEXT, full_path);
+                       break;
                case IDC_DF0:
                case IDC_DF0QQ:
                        selectdisk (prefs, hDlg, 0, IDC_DF0TEXT, full_path);
@@ -4777,6 +4811,7 @@ static void init_quickstartdlg (HWND hDlg)
                        workprefs.df[2][0] = 0;
                        workprefs.df[3][0] = 0;
                        workprefs.cdimagefile[0] = 0;
+                       workprefs.cdimagefileuse = quickstart_cdtype > 0;
                        load_quickstart (hDlg, 1);
                        quickstarthost (hDlg, hostconf);
                }
@@ -4907,7 +4942,7 @@ static void testimage (HWND hDlg, int num)
                break;
        case 11:
                quickstart_ok_floppy = 1;
-               if (quickstart_model != 1 && quickstart_model != 2 && quickstart_model != 4) {
+               if (quickstart_model != 1 && quickstart_model != 2 && quickstart_model != 4 && quickstart_model != 5 && quickstart_model != 6 && quickstart_model != 8) {
                        quickstart_model = 4;
                        messageid = IDS_IMGCHK_KS2;
                        reload = 1;
@@ -5021,8 +5056,8 @@ static INT_PTR CALLBACK QuickstartDlgProc (HWND hDlg, UINT msg, WPARAM wParam, L
                                                SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, WM_GETTEXT, (WPARAM)len, (LPARAM)quickstart_cddrive);
                                                _tcscpy (workprefs.cdimagefile, quickstart_cddrive);
                                        } else {
-                                               workprefs.cdimagefile[0] = 0;
-                                               quickstart_cddrive[0] = 0;
+                                               eject_cd ();
+                                               quickstart_cdtype = val;
                                        }
                                        addfloppytype (hDlg, 1);
                                        addfloppyhistory (hDlg);
@@ -7175,12 +7210,13 @@ extern const TCHAR *get_aspi_path (int);
 static void misc_scsi (HWND hDlg)
 {
        SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_RESETCONTENT, 0, 0);
+       SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_ADDSTRING, 0, (LPARAM)L"SCSI Emulation");
        SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_ADDSTRING, 0, (LPARAM)L"SPTI *");
        SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_ADDSTRING, 0, (LPARAM)L"SPTI + SCSI SCAN");
        SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_ADDSTRING, 0, (LPARAM)((get_aspi_path (0)) ? L"AdaptecASPI" : L"(AdaptecASPI)"));
        SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_ADDSTRING, 0, (LPARAM)((get_aspi_path (1)) ? L"NeroASPI" : L"(NeroASPI)"));
        SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_ADDSTRING, 0, (LPARAM)((get_aspi_path (2)) ? L"FrogASPI" : L"(FrogASPI)"));
-       SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_SETCURSEL, workprefs.win32_uaescsimode - 1, 0);
+       SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_SETCURSEL, workprefs.win32_uaescsimode, 0);
 }
 
 static void misc_lang (HWND hDlg)
@@ -7409,7 +7445,7 @@ static INT_PTR MiscDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
                                case IDC_SCSIMODE:
                                        v = SendDlgItemMessage (hDlg, IDC_SCSIMODE, CB_GETCURSEL, 0, 0L);
                                        if (v != CB_ERR)
-                                               workprefs.win32_uaescsimode = v + 1;
+                                               workprefs.win32_uaescsimode = v;
                                        break;
                                }
                        }
@@ -9059,9 +9095,21 @@ static ACCEL HarddiskAccel[] = {
        { 0, 0, 0 }
 };
 
-static void harddiskdlg_button (HWND hDlg, int button)
+static void harddiskdlg_button (HWND hDlg, WPARAM wParam)
 {
+       int button = LOWORD (wParam);
        switch (button) {
+       case IDC_CD_SELECT:
+               DiskSelection (hDlg, wParam, 17, &workprefs, NULL);
+               quickstart_cdtype = 1;
+               workprefs.cdimagefileuse = true;
+               addcdtype (hDlg, IDC_CD_TYPE);
+               break;
+       case IDC_CD_EJECT:
+               eject_cd ();
+               SetDlgItemText (hDlg, IDC_CD_TEXT, L"");
+               addcdtype (hDlg, IDC_CD_TYPE);
+               break;
        case IDC_NEW_FS:
                current_fsvdlg = empty_fsvdlg;
                archivehd = 0;
@@ -9200,6 +9248,8 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                CheckDlgButton (hDlg, IDC_MAPDRIVES_REMOVABLE, workprefs.win32_automount_removabledrives);
                CheckDlgButton (hDlg, IDC_NOUAEFSDB, workprefs.filesys_no_uaefsdb);
                CheckDlgButton (hDlg, IDC_NORECYCLEBIN, workprefs.win32_norecyclebin);
+               addfloppyhistory_2 (hDlg, 0, IDC_CD_TEXT, HISTORY_CD);
+               addcdtype (hDlg, IDC_CD_TYPE);
                InitializeListView (hDlg);
                hilitehd ();
                break;
@@ -9222,21 +9272,55 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                }
 
        case WM_COMMAND:
-               switch (LOWORD(wParam))
-               {
-               case 10001:
-                       clicked_entry--;
-                       hilitehd ();
-                       break;
-               case 10002:
-                       clicked_entry++;
-                       hilitehd ();
-                       break;
-               default:
-                       harddiskdlg_button (hDlg, LOWORD (wParam));
-                       InitializeListView (hDlg);
-                       hilitehd ();
+               if (HIWORD (wParam) == CBN_SELCHANGE || HIWORD (wParam) == CBN_KILLFOCUS)  {
+                       switch (LOWORD (wParam))
+                       {
+                       case IDC_CD_TEXT:
+                       getfloppyname (hDlg, 0, 1, IDC_CD_TEXT);
+                       quickstart_cdtype = 1;
+                       workprefs.cdimagefileuse = true;
+                       addcdtype (hDlg, IDC_CD_TYPE);
+                       addfloppyhistory_2 (hDlg, 0, IDC_CD_TEXT, HISTORY_CD);
+                       break;
+                       case IDC_CD_TYPE:
+                       int val = SendDlgItemMessage (hDlg, IDC_CD_TYPE, CB_GETCURSEL, 0, 0);
+                       if (val != CB_ERR) {
+                               quickstart_cdtype = val;
+                               if (quickstart_cdtype >= 2) {
+                                       int len = sizeof quickstart_cddrive / sizeof (TCHAR);
+                                       quickstart_cdtype = 2;
+                                       workprefs.cdimagefileuse = true;
+                                       SendDlgItemMessage (hDlg, IDC_CD_TYPE, WM_GETTEXT, (WPARAM)len, (LPARAM)quickstart_cddrive);
+                                       _tcscpy (workprefs.cdimagefile, quickstart_cddrive);
+                               } else {
+                                       eject_cd ();
+                                       quickstart_cdtype = val;
+                                       if (val > 0)
+                                               workprefs.cdimagefileuse = true;
+
+                               }
+                               addcdtype (hDlg, IDC_CD_TYPE);
+                               addfloppyhistory_2 (hDlg, 0, IDC_CD_TEXT, HISTORY_CD);
+                       }
                        break;
+                       }
+               } else {
+                       switch (LOWORD(wParam))
+                       {
+                       case 10001:
+                               clicked_entry--;
+                               hilitehd ();
+                               break;
+                       case 10002:
+                               clicked_entry++;
+                               hilitehd ();
+                               break;
+                       default:
+                               harddiskdlg_button (hDlg, wParam);
+                               InitializeListView (hDlg);
+                               hilitehd ();
+                               break;
+                       }
                }
                break;
 
@@ -9305,23 +9389,21 @@ static void floppytooltip (HWND hDlg, int num, uae_u32 crc32)
        SendMessage (ToolTipHWND, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
 }
 
-static void addfloppyhistory_2 (HWND hDlg, int n, int f_text)
+static void addfloppyhistory_2 (HWND hDlg, int n, int f_text, int type)
 {
        int i, j;
        TCHAR *s, *text;
        UAEREG *fkey;
-       int nn, type, curidx;
+       int nn, curidx;
 
        if (f_text < 0)
                return;
        SendDlgItemMessage (hDlg, f_text, CB_RESETCONTENT, 0, 0);
-       if (iscd (n)) {
+       if (type == HISTORY_CD) {
                nn = 1;
-               type = HISTORY_CD;
                text = workprefs.cdimagefile;
        } else {
                nn = workprefs.dfxtype[n] + 1;
-               type = HISTORY_FLOPPY;
                text = workprefs.df[n];
        }
        SendDlgItemMessage (hDlg, f_text, WM_SETTEXT, 0, (LPARAM)text);
@@ -9387,18 +9469,38 @@ static void addfloppyhistory (HWND hDlg)
                        f_text = floppybuttons[n][0];
                else
                        f_text = IDC_DISKTEXT;
-               addfloppyhistory_2 (hDlg, n, f_text);
+               addfloppyhistory_2 (hDlg, n, f_text, iscd (n) ? HISTORY_CD : HISTORY_FLOPPY);
        }
 }
 
-static void ejectfloppy (int n)
+static void addcdtype (HWND hDlg, int id)
 {
-       if (iscd (n)) {
-               workprefs.cdimagefile[0] = 0;
-               quickstart_cdtype = 0;
-       } else {
-               workprefs.df[n][0] = 0;
+       TCHAR tmp[MAX_DPATH];
+       SendDlgItemMessage (hDlg, id, CB_RESETCONTENT, 0, 0L);
+       WIN32GUI_LoadUIString (IDS_QS_CD_AUTO, tmp, sizeof tmp / sizeof (TCHAR));
+       SendDlgItemMessage (hDlg, id, CB_ADDSTRING, 0, (LPARAM)tmp);
+       WIN32GUI_LoadUIString (IDS_QS_CD_IMAGE, tmp, sizeof tmp / sizeof (TCHAR));
+       SendDlgItemMessage (hDlg, id, CB_ADDSTRING, 0, (LPARAM)tmp);
+       int cdtype = quickstart_cdtype;
+       if (currentpage != QUICKSTART_ID) {
+               if (full_property_sheet && !workprefs.cdimagefileuse && !workprefs.cdimagefile[0])
+                       cdtype = 0;
+       }
+       int cnt = 2;
+       for (int drive = 'C'; drive <= 'Z'; ++drive) {
+               TCHAR vol[100];
+               _stprintf (vol, L"%c:\\", drive);
+               int drivetype = GetDriveType (vol);
+               if (drivetype == DRIVE_CDROM) {
+                       SendDlgItemMessage (hDlg, id, CB_ADDSTRING, 0, (LPARAM)vol);
+                       if (!_tcsicmp (vol, quickstart_cddrive)) {
+                               cdtype = quickstart_cdtype = cnt;
+                               _tcscpy (workprefs.cdimagefile, vol);
+                       }
+                       cnt++;
+               }
        }
+       SendDlgItemMessage (hDlg, id, CB_SETCURSEL, cdtype, 0);
 }
 
 static void addfloppytype (HWND hDlg, int n)
@@ -9437,29 +9539,7 @@ static void addfloppytype (HWND hDlg, int n)
                        ew (hDlg, f_enable, FALSE);
                        WIN32GUI_LoadUIString (IDS_QS_CD, tmp, sizeof tmp / sizeof (TCHAR));
                        SetWindowText (GetDlgItem (hDlg, f_enable), tmp);
-                       SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, CB_RESETCONTENT, 0, 0L);
-                       WIN32GUI_LoadUIString (IDS_QS_CD_AUTO, tmp, sizeof tmp / sizeof (TCHAR));
-                       SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, CB_ADDSTRING, 0, (LPARAM)tmp);
-                       WIN32GUI_LoadUIString (IDS_QS_CD_IMAGE, tmp, sizeof tmp / sizeof (TCHAR));
-                       SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, CB_ADDSTRING, 0, (LPARAM)tmp);
-                       quickstart_cdtype = 0;
-                       if (workprefs.cdimagefile[0])
-                               quickstart_cdtype = 1;
-                       int cnt = 2;
-                       for (int drive = 'C'; drive <= 'Z'; ++drive) {
-                               TCHAR vol[100];
-                               _stprintf (vol, L"%c:\\", drive);
-                               int drivetype = GetDriveType (vol);
-                               if (drivetype == DRIVE_CDROM) {
-                                       SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, CB_ADDSTRING, 0, (LPARAM)vol);
-                                       if (!_tcsicmp (vol, quickstart_cddrive)) {
-                                               quickstart_cdtype = cnt;
-                                               _tcscpy (workprefs.cdimagefile, vol);
-                                       }
-                                       cnt++;
-                               }
-                       }
-                       SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, CB_SETCURSEL, quickstart_cdtype, 0);
+                       addcdtype (hDlg, IDC_CD0Q_TYPE);
                        hide (hDlg, IDC_CD0Q_TYPE, 0);
                        text = workprefs.cdimagefile;
                        regsetstr (NULL, L"QuickStartCDDrive", quickstart_cdtype >= 2 ? quickstart_cddrive : L"");
@@ -9580,10 +9660,8 @@ static int getfloppybox (HWND hDlg, int f_text, TCHAR *out, int maxlen, int type
        return out[0] ? 1 : 0;
 }
 
-static void getfloppyname (HWND hDlg, int n)
+static void getfloppyname (HWND hDlg, int n, int cd, int f_text)
 {
-       int f_text = currentpage == QUICKSTART_ID ? floppybuttonsq[n][0] : floppybuttons[n][0];
-       int cd = iscd (n);
        TCHAR tmp[MAX_DPATH];
 
        if (getfloppybox (hDlg, f_text, tmp, sizeof (tmp) / sizeof (TCHAR), cd ? HISTORY_CD : HISTORY_FLOPPY)) {
@@ -9591,14 +9669,18 @@ static void getfloppyname (HWND hDlg, int n)
                        disk_insert (n, tmp);
                        _tcscpy (workprefs.df[n], tmp);
                } else {
-                       if (quickstart_cddrive[0]) {
-                               quickstart_cdtype = 0;
-                               quickstart_cddrive[0] = 0;
-                       }
+                       if (quickstart_cddrive[0])
+                               eject_cd ();
                        _tcscpy (workprefs.cdimagefile, tmp);
                }
        }
 }
+static void getfloppyname (HWND hDlg, int n)
+{
+       int cd = iscd (n);
+       int f_text = currentpage == QUICKSTART_ID ? floppybuttonsq[n][0] : floppybuttons[n][0];
+       getfloppyname (hDlg, n, cd, f_text);
+}
 
 static void addallfloppies (HWND hDlg)
 {
@@ -10165,7 +10247,7 @@ static INT_PTR CALLBACK SwapperDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPAR
 static PRINTER_INFO_1 *pInfo = NULL;
 static DWORD dwEnumeratedPrinters = 0;
 #define MAX_PRINTERS 10
-struct serialportinfo comports[MAX_SERIAL_PORTS];
+struct serparportinfo comports[MAX_SERPAR_PORTS];
 static int ghostscript_available;
 
 static int joyxprevious[4];
@@ -10549,7 +10631,7 @@ static void values_to_portsdlg (HWND hDlg)
        } else {
                int i;
                LRESULT result = -1;
-               for (i = 0; i < MAX_SERIAL_PORTS && comports[i].name; i++) {
+               for (i = 0; i < MAX_SERPAR_PORTS && comports[i].name; i++) {
                        if (!_tcscmp (comports[i].dev, workprefs.sername)) {
                                result = SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, i + 1, 0L);
                                break;
@@ -10605,7 +10687,7 @@ static void init_portsdlg (HWND hDlg)
 
        SendDlgItemMessage (hDlg, IDC_SERIAL, CB_RESETCONTENT, 0, 0L);
        SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM)szNone.c_str());
-       for (port = 0; port < MAX_SERIAL_PORTS && comports[port].name; port++) {
+       for (port = 0; port < MAX_SERPAR_PORTS && comports[port].name; port++) {
                SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM)comports[port].name);
        }
 
index ce36832f9fee00a8622d8b9d467f610e95c97748..7674f44e816f68971011a825d48633e068673f90 100644 (file)
     <ClCompile Include="..\lcd.cpp" />
     <ClCompile Include="..\midi.cpp" />
     <ClCompile Include="..\mman.cpp" />
+    <ClCompile Include="..\mp3decoder.cpp" />
     <ClCompile Include="..\parser.cpp" />
     <ClCompile Include="..\picasso96_win.cpp" />
     <ClCompile Include="..\posixemu.cpp" />
index a7858e1f0dcafa9ddfd1d0b7d8cca43990815048..60909705907c1ae6cfd204afdc3993827bcb39e5 100644 (file)
     <ClCompile Include="..\..\cpuemu_21.cpp">
       <Filter>common</Filter>
     </ClCompile>
+    <ClCompile Include="..\mp3decoder.cpp">
+      <Filter>win32</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\resources\35floppy.ico">
index a3e256bba93fb426b2fcd9b0c2db7e12d10570fb..d079ec5d9a811238ec653608266482624a13febe 100644 (file)
@@ -1,5 +1,69 @@
 
 
+- most debugger options now accept .b, .w and .l size extension (+special .3 if 3-byte word),
+  old style separate size values (1, 2, 3 or 4) not supported anymore
+- debugger 'w' memory freeze mode improved, now also works with copper writes,
+  word and long size freeze values work properly
+- fixed right border corruption when horizontal centering enabled
+- filesystem access problems fixed (b2, forgotten test code..)
+- another "too fast CPU" hack re-added to audio code
+- quickstart "disk image requires ks2.0+" message ignored A3000/A4000/CD32 configurations
+- skip DMAL emulation in JIT modes
+- rawinput supports rawinput packets that have zero scancode but virtual keycode set or
+  null device handle (for example some software injected keys and some keyboard media keys),
+  packets with null device handle are redirected to new "winuae null keyboard"
+
+Major updates in CD related options, IOCTL access, built-in image mounter, CD32, CDTV,
+uaescsi.device:
+
+- cd rom image and IOCTL handling rewritten, unified toc and subchannel data structures
+- cd drive/image selection added to harddrives panel (quickstart duplicate, temporary
+  location until real CD selection panel is done.. if ever..)  Use this to switch images
+  and drives on the fly, report if switching causes crashes or weird behavior.
+  NOTE: only unit 0 supported in uaescsi.device mode, other units are immediately put
+  to "no disk" state when this option is used for the first time.
+- quickstart/harddrives CD "image mode" selected with blank select box: enable image
+  drive without media
+- always use IOCTL in CD32/CDTV modes
+- only enumarate SPTI devices when uaescsi.device is enabled
+- subchannel support added to IOCTL CDROM handling (CD+G)
+- CloneCD (.ccd) CD image file support added, including subchannel files
+- CD32 CD subchannel DMA channel emulated, CD+G audio CDs supported
+- CD32 CD end of play notification only worked if play command was last packet sent
+- many CD32 and CDTV on the fly drive/image/media change updates again
+- CDTV statefile support added
+- CDTV 6525 (CIA-like 3-port IO chip/interrupt controller) emulation rewritten
+- CDTV CD subchannel hardware emulated (CD+G, see notes below)
+- added CDTV front panel CD player buttons to input event list (they directly control
+  CD mechanism and they are the only buttons that work in CD+G mode)
+- "regular" CDTV remote Play/Stop/etc.. input events emulate front panel buttons when CD drive
+  receives enable front panel command, sends "normal" keycodes when frontpanel is disabled
+- simple SCSI emulation added to image mounter in uaescsi.device mode (no CD audio support yet)
+  simple means: CDFS in SCSI mode should work with mounted images now, nothing more.
+  (TEST UNIT READY, READ [6,10,12], READ TOC, INQUIRY, READ CAPACITY emulated. Audio CD commands
+  will be implemented in later betas)
+- added SCSI emulation option to SCSI GUI panel, enables SCSI emulation when using real drives
+- uaescsi.device mounted image file changed without CMD_ADDCHANGEINT or CMD_REMOVE media change
+  interrups: use long 8 second media change delay (CDFS default poll time is ~5s)
+
+CD+G notes:
+
+Some subchannel packets will be lost if emulation slows down too much.
+CD+G confirmed working, CD+MIDI should also work but not tested.
+
+CD32 CD+G mode starts automatically, button also in main audio CD screen.
+
+CDTV needs extra steps: In audio CD player screen select "TV/Keyboard" icon in bottom
+right corner, then press front panel Play-button, only front panel buttons are accepted
+at this point. NOTE: CDTV CD+G does not (yet) work in cycle-exact mode.
+
+CD32 and CDTV do not correctly handle all CD+G discs, it seems both miss first few subchannel
+packets at the beginning.. Confirmed on real CD32 and CDTV. They do work in emulation
+if playback start position is about 1s earlier than asked but this hack is disabled
+because it can cause cd audio sync issues in games.
+
+Beta 2:
+
 - CD32/CDTV image mounting broke in b1 (can still be broken in some situations)
 - new audio state machine emulation froze in some situations
 - re-added "too fast CPU" hack that fixes missing sounds with sound routines that use CPU loops
index 26f3e4f7f331f36bfce51a6a87cdfb8d761f5707..be8f1d541033e841b7a5b993f4662101e80105f0 100644 (file)
--- a/sana2.cpp
+++ b/sana2.cpp
@@ -229,11 +229,6 @@ static struct priv_devstruct pdevst[MAX_OPEN_DEVICES];
 static uae_u32 nscmd_cmd;
 static uae_sem_t change_sem, async_sem;
 
-static struct device_info *devinfo (int mode, int unitnum, struct device_info *di)
-{
-       return sys_command_info (mode, unitnum, di);
-}
-
 static struct devstruct *getdevstruct (int unit)
 {
        if (unit >= MAX_TOTAL_NET_DEVICES || unit < 0)
index 04b9e66c3e857eef804eda1e8f6c3dd596de36b7..89133feca32d978c1d7cc19dc85a486f5302060c 100644 (file)
@@ -573,6 +573,8 @@ void restore_state (const TCHAR *filename)
 #ifdef CDTV
                else if (!_tcscmp (name, L"CDTV"))
                        end = restore_cdtv (chunk);
+               else if (!_tcscmp (name, L"DMAC"))
+                       end = restore_dmac (chunk);
 #endif
                else if (!_tcscmp (name, L"GAYL"))
                        end = restore_gayle (chunk);
@@ -832,6 +834,9 @@ int save_state (const TCHAR *filename, const TCHAR *description)
        xfree (dst);
 #endif
 #ifdef CDTV
+       dst = save_dmac (&len);
+       save_chunk (f, dst, len, L"DMAC", 0);
+       xfree (dst);
        dst = save_cdtv (&len);
        save_chunk (f, dst, len, L"CDTV", 0);
        xfree (dst);
index 35c73013381266a7bd0b30594aa49150777ef00c..188463cd62a13c2d7d9ab94a10935fa143156e36 100644 (file)
@@ -79,7 +79,7 @@ static uae_sem_t change_sem;
 
 static struct device_info *devinfo (int mode, int unitnum, struct device_info *di)
 {
-       return sys_command_info (mode, unitnum, di);
+       return sys_command_info (mode, unitnum, di, 0);
 }
 
 static void io_log (const TCHAR *msg, uaecptr request)
@@ -302,7 +302,7 @@ static int scsiemul_switchscsi (const TCHAR *name)
                while (i < MAX_TOTAL_DEVICES && dev == NULL) {
                        discsi = 0;
                        if (sys_command_open (mode, i)) {
-                               discsi = sys_command_info (mode, i, &discsi2);
+                               discsi = sys_command_info (mode, i, &discsi2, 0);
                                if (discsi && discsi->type == INQ_ROMD) {
                                        if (!_tcsicmp (currprefs.cdimagefile, discsi->label)) {
                                                dev = &devst[0];
@@ -319,7 +319,7 @@ static int scsiemul_switchscsi (const TCHAR *name)
                                                }
                                                if (dev->di.media_inserted) {
                                                        dev->di.media_inserted = 0;
-                                                       scsi_do_disk_change (dev->di.id, 1);
+                                                       scsi_do_disk_change (dev->di.id, 1, NULL);
                                                }
                                        }
                                }
@@ -342,10 +342,10 @@ static int scsiemul_switchemu (const TCHAR *name)
                return -1;
        int opened = sys_command_isopen (0);
        if (sys_command_open (DF_IOCTL, 0)) {
-               if (discsi = sys_command_info (DF_IOCTL, 0, &discsi2)) {
+               if (discsi = sys_command_info (DF_IOCTL, 0, &discsi2, 0)) {
                        dev = &devst[0];
                        dev->unitnum = 0;
-                       dev->allow_scsi = 0;
+                       dev->allow_scsi = 1;
                        dev->allow_ioctl = 1;
                        dev->drivetype = discsi->type;
                        memcpy (&dev->di, discsi, sizeof (struct device_info));
@@ -374,7 +374,8 @@ int scsi_do_disk_device_change (void)
 }
 
 // device_id = -1 and insert==0 -> all medias going away
-int scsi_do_disk_change (int device_id, int insert)
+// pollmode is 1 if no change interrupts found -> increase time of media change
+int scsi_do_disk_change (int device_id, int insert, int *pollmode)
 {
        int i, j, ret;
 
@@ -387,6 +388,8 @@ int scsi_do_disk_change (int device_id, int insert)
                if (dev->di.id == device_id || (device_id < 0 && i == 0)) {
                        ret = i;
                        if ((dev->di.media_inserted > 0 && insert == 0) || (dev->di.media_inserted <= 0 && insert)) {
+                               if (pollmode)
+                                       *pollmode = 1;
                                if (dev->aunit >= 0) {
                                        struct priv_devstruct *pdev = &pdevst[dev->aunit];
                                        devinfo (pdev->mode, dev->unitnum, &dev->di);
@@ -398,11 +401,16 @@ int scsi_do_disk_change (int device_id, int insert)
                                while (j < MAX_ASYNC_REQUESTS) {
                                        if (dev->d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
                                                uae_Cause (dev->d_request_data[j]);
+                                               if (pollmode)
+                                                       *pollmode = 0;
                                        }
                                        j++;
                                }
-                               if (dev->changeint)
+                               if (dev->changeint) {
                                        uae_Cause (dev->changeint);
+                                       if (pollmode)
+                                               *pollmode = 0;
+                               }
                        }
                }
        }
@@ -483,7 +491,7 @@ static int command_read (int mode, struct devstruct *dev, uaecptr data, uae_u64
        length /= blocksize;
        offset /= blocksize;
        while (length > 0) {
-               temp = sys_command_read (mode, dev->unitnum, offset);
+               temp = sys_command_read (mode, dev->unitnum, NULL, offset, 1);
                if (!temp)
                        return 20;
                memcpyha_safe (data, temp, blocksize);
@@ -499,14 +507,14 @@ static int command_write (int mode, struct devstruct *dev, uaecptr data, uae_u64
        uae_u32 blocksize = dev->di.bytespersector;
        struct device_scsi_info dsi;
 
-       if (!sys_command_scsi_info(mode, dev->unitnum, &dsi))
+       if (!sys_command_scsi_info (mode, dev->unitnum, &dsi))
                return 20;
        length /= blocksize;
        offset /= blocksize;
        while (length > 0) {
                int err;
                memcpyah_safe (dsi.buffer, data, blocksize);
-               err = sys_command_write (mode, dev->unitnum, offset);
+               err = sys_command_write (mode, dev->unitnum, NULL, offset, 1);
                if (!err)
                        return 20;
                if (err < 0)
@@ -530,7 +538,7 @@ static int command_cd_read (int mode, struct devstruct *dev, uaecptr data, uae_u
        offset -= startoffset;
        sector = offset / dev->di.bytespersector;
        while (length > 0) {
-               temp = sys_command_cd_read (mode, dev->unitnum, sector);
+               temp = sys_command_cd_read (mode, dev->unitnum, NULL, sector, 1);
                if (!temp)
                        return 20;
                if (startoffset > 0) {
@@ -928,7 +936,7 @@ static void dev_reset (void)
                                }
                        }
                        if (mode >= 0) {
-                               discsi = sys_command_info (mode, j, &discsi2);
+                               discsi = sys_command_info (mode, j, &discsi2, 0);
                                sys_command_close (mode, j);
                        }
                        if (discsi) {
index 2d3f89142bf15ef288a3d94e9aec4c46cc6ba323..53d754f25edaf6b73c4982bdbded99852ea94bc3 100644 (file)
--- a/zfile.cpp
+++ b/zfile.cpp
@@ -1860,6 +1860,7 @@ struct zfile *zfile_dup (struct zfile *zf)
                nzf->zipname = my_strdup (zf->zipname);
        nzf->zfdmask = zf->zfdmask;
        nzf->mode = my_strdup (zf->mode);
+       nzf->size = zf->size;
        return nzf;
 }