]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
2210b4
authorToni Wilen <twilen@winuae.net>
Sun, 18 Jul 2010 15:19:39 +0000 (18:19 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 18 Jul 2010 15:19:39 +0000 (18:19 +0300)
29 files changed:
a2091.cpp
akiko.cpp
blkdev.cpp
blkdev_cdimage.cpp
cdtv.cpp
cfgfile.cpp
custom.cpp
drawing.cpp
filesys.cpp
include/blkdev.h
include/custom.h
include/execio.h
include/options.h
include/scsidev.h
main.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/posixemu.cpp
od-win32/rp.cpp
od-win32/win32.cpp
od-win32/win32.h
od-win32/win32gui.cpp
od-win32/winuaechangelog.txt
scsi.cpp
scsiemul.cpp
zfile_archive.cpp

index fe1b481648215d2d5481036be10465fbe66a4ace..2a07e7af6b6c44ed01fab153dae8cc65f8e23256 100644 (file)
--- a/a2091.cpp
+++ b/a2091.cpp
@@ -1225,23 +1225,23 @@ static void freenativescsi (void)
 static void addnativescsi (void)
 {
        int i, j;
-       int devices[MAX_TOTAL_DEVICES];
-       int types[MAX_TOTAL_DEVICES];
-       struct device_info dis[MAX_TOTAL_DEVICES];
+       int devices[MAX_TOTAL_SCSI_DEVICES];
+       int types[MAX_TOTAL_SCSI_DEVICES];
+       struct device_info dis[MAX_TOTAL_SCSI_DEVICES];
 
        freenativescsi ();
        i = 0;
-       while (i < MAX_TOTAL_DEVICES) {
+       while (i < MAX_TOTAL_SCSI_DEVICES) {
                types[i] = -1;
                devices[i] = -1;
-               if (sys_command_open (DF_SCSI, i)) {
-                       if (sys_command_info (DF_SCSI, i, &dis[i], 0)) {
+               if (sys_command_open (i)) {
+                       if (sys_command_info (i, &dis[i], 0)) {
                                devices[i] = i;
                                types[i] = 100 - i;
                                if (dis[i].type == INQ_ROMD)
                                        types[i] = 1000 - i;
                        }
-                       sys_command_close (DF_SCSI, i);
+                       sys_command_close (i);
                }
                i++;
        }
index c3a7396defc98c5d0db9fd53be82c606ae2ac0f3..22f752921076c6c913004c85c67308ccc63be831 100644 (file)
--- a/akiko.cpp
+++ b/akiko.cpp
@@ -454,9 +454,9 @@ static void cdaudiostop_do (void)
        cdrom_paused = 0;
        if (unitnum < 0)
                return;
-       sys_command_cd_pause (DF_IOCTL, unitnum, 0);
-       sys_command_cd_stop (DF_IOCTL, unitnum);
-       sys_command_cd_pause (DF_IOCTL, unitnum, 1);
+       sys_command_cd_pause (unitnum, 0);
+       sys_command_cd_stop (unitnum);
+       sys_command_cd_pause (unitnum, 1);
 }
 
 static void cdaudiostop (void)
@@ -512,7 +512,8 @@ static void cdaudioplay_do (void)
        qcode_valid = 0;
        if (unitnum < 0)
                return;
-       sys_command_cd_play (DF_IOCTL, unitnum, startlsn, endlsn, scan, subfunc);
+       sys_command_cd_pause (unitnum, 0);
+       sys_command_cd_play (unitnum, startlsn, endlsn, scan, subfunc);
 }
 
 static bool isaudiotrack (int startlsn)
@@ -623,17 +624,14 @@ static int get_cdrom_toc (void)
 {
        int j;
        int datatrack = 0, secondtrack = 0;
-       struct cd_toc_head *th;
 
        cdrom_toc_counter = -1;
-       th = sys_command_cd_toc (DF_IOCTL, unitnum);
-       if (!th)
+       if (!sys_command_cd_toc (unitnum, &cdrom_toc_cd_buffer))
                return 1;
-       memcpy (&cdrom_toc_cd_buffer, th, sizeof cdrom_toc_cd_buffer);
        memset (cdrom_toc_buffer, 0, MAX_TOC_ENTRIES * 13);
        cdrom_data_end = -1;
-       for (j = 0; j < th->points; j++) {
-               struct cd_toc *s = &th->toc[j];
+       for (j = 0; j < cdrom_toc_cd_buffer.points; j++) {
+               struct cd_toc *s = &cdrom_toc_cd_buffer.toc[j];
                uae_u8 *d = &cdrom_toc_buffer[j * 13];
                int addr = s->paddress;
                int msf = lsn2msf (addr);
@@ -666,32 +664,34 @@ static int sys_cddev_open (void)
        struct device_info di1, *di2;
        int cd32unit = -1;
        int audiounit = -1;
-       int opened[MAX_TOTAL_DEVICES];
+       int opened[MAX_TOTAL_SCSI_DEVICES];
        int i;
 
-       for (unitnum = 0; unitnum < MAX_TOTAL_DEVICES; unitnum++) {
+       for (unitnum = 0; unitnum < MAX_TOTAL_SCSI_DEVICES; unitnum++) {
                opened[unitnum] = 0;
-               if (sys_command_open (DF_IOCTL, unitnum)) {
+               if (sys_command_open (unitnum)) {
                        opened[unitnum] = 1;
-                       di2 = sys_command_info (DF_IOCTL, unitnum, &di1, 0);
+                       di2 = sys_command_info (unitnum, &di1, 0);
                        if (di2 && di2->type == INQ_ROMD) {
                                write_log (L"%s: ", di2->label);
                                if (first < 0)
                                        first = unitnum;
                                if (!get_cdrom_toc ()) {
                                        if (cdrom_data_end > 0) {
-                                               uae_u8 *p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, 16, 1);
-                                               if (p) {
+                                               uae_u8 buffer[2048];
+                                               if (sys_command_cd_read (unitnum, buffer, 16, 1)) {
+                                                       uae_u8 *p = buffer;
                                                        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, NULL, 21, 1);
-                                                               crc = get_crc32 (p, 2048);
-                                                               if (crc == 0xe56c340f)
-                                                                       write_log (L" [CD32.TM]");
-                                                               write_log (L"\n");
+                                                               if (sys_command_cd_read (unitnum, buffer, 21, 1)) {
+                                                                       crc = get_crc32 (buffer, 2048);
+                                                                       if (crc == 0xe56c340f)
+                                                                               write_log (L" [CD32.TM]");
+                                                                       write_log (L"\n");
+                                                               }
                                                        } else {
                                                                write_log (L"non CD32/CDTV data CD\n");
                                                        }
@@ -716,19 +716,19 @@ static int sys_cddev_open (void)
                unitnum = first;
        if (unitnum >= 0)
                opened[unitnum] = 0;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                if (opened[i])
-                       sys_command_close (DF_IOCTL, i);
+                       sys_command_close (i);
        }
        if (unitnum < 0)
                return 1;
-       di2 = sys_command_info (DF_IOCTL, unitnum, &di1, 0);
+       di2 = sys_command_info (unitnum, &di1, 0);
        if (!di2) {
                write_log (L"unit %d info failed\n", unitnum);
-               sys_command_close (DF_IOCTL, unitnum);
+               sys_command_close (unitnum);
                return 1;
        }
-       if (sys_command_ismedia (DF_IOCTL, unitnum, 0) <= 0)
+       if (sys_command_ismedia (unitnum, 0) <= 0)
                cd_hunt = 1;
        write_log (L"using drive %s (unit %d, media %d)\n", di2->label, unitnum, di2->media_inserted);
        /* make sure CD audio is not playing */
@@ -740,7 +740,7 @@ static int sys_cddev_open (void)
 static void sys_cddev_close (void)
 {
        cdaudiostop_do ();
-       sys_command_close (DF_IOCTL, unitnum);
+       sys_command_close (unitnum);
 }
 
 static int command_lengths[] = { 1,2,1,1,12,2,1,1,4,1,-1,-1,-1,-1,-1,-1 };
@@ -806,7 +806,7 @@ static int cdrom_command_media_status (void)
        if (cd_hunt) {
                cdrom_result_buffer[1] = 0x80;
        } else {
-               cdrom_result_buffer[1] = sys_command_ismedia (DF_IOCTL, unitnum, 0) > 0 ? 0x83: 0x80;
+               cdrom_result_buffer[1] = sys_command_ismedia (unitnum, 0) > 0 ? 0x83: 0x80;
        }
        return 2;
 }
@@ -1189,28 +1189,28 @@ static void akiko_internal (void)
 static void do_hunt (void)
 {
        int i;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               if (sys_command_ismedia (DF_IOCTL, i, 1) > 0)
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (sys_command_ismedia (i, 1) > 0)
                        break;
        }
-       if (i == MAX_TOTAL_DEVICES) {
-               if (unitnum >= 0 && sys_command_ismedia (DF_IOCTL, unitnum, 1) >= 0)
+       if (i == MAX_TOTAL_SCSI_DEVICES) {
+               if (unitnum >= 0 && sys_command_ismedia (unitnum, 1) >= 0)
                        return;
-               for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-                       if (sys_command_ismedia (DF_IOCTL, i, 1) >= 0)
+               for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+                       if (sys_command_ismedia (i, 1) >= 0)
                                break;
                }
-               if (i == MAX_TOTAL_DEVICES)
+               if (i == MAX_TOTAL_SCSI_DEVICES)
                        return;
        }
        if (unitnum >= 0) {
                int ou = unitnum;
                unitnum = -1;
-               sys_command_close (DF_IOCTL, ou);
+               sys_command_close (ou);
        }
-       if (sys_command_open (DF_IOCTL, i) > 0) {
+       if (sys_command_open (i) > 0) {
                struct device_info di = { 0 };
-               sys_command_info (DF_IOCTL, i, &di, 0);
+               sys_command_info (i, &di, 0);
                unitnum = i;
                cd_hunt = 0;
                lastmediastate = -1;
@@ -1225,7 +1225,7 @@ void AKIKO_hsync_handler (void)
 
        if (cd_hunt) {
                static int huntcnt;
-               if (huntcnt <= 0 && !mediachanged) {
+               if (huntcnt <= 0 && (!mediachanged || unitnum < 0)) {
                        do_hunt ();
                        huntcnt = 312 * 50 * 2;
                }
@@ -1296,7 +1296,6 @@ static void *akiko_thread (void *null)
        uae_u8 *tmp1;
        uae_u8 *tmp2;
        int tmp3;
-       uae_u8 *p;
        int offset;
        int sector;
 
@@ -1307,19 +1306,19 @@ static void *akiko_thread (void *null)
                        switch (b)
                        {
                        case 0x0102: // pause
-                               sys_command_cd_pause (DF_IOCTL, unitnum, 1);
+                               sys_command_cd_pause (unitnum, 1);
                                break;
                        case 0x0103: // unpause
-                               sys_command_cd_pause (DF_IOCTL, unitnum, 0);
+                               sys_command_cd_pause (unitnum, 0);
                                break;
                        case 0x0104: // stop
                                cdaudiostop_do ();
                                break;
                        case 0x0105: // mute change
-                               sys_command_cd_volume (DF_IOCTL, unitnum, cdrom_muted ? 0 : 0xffff);
+                               sys_command_cd_volume (unitnum, cdrom_muted ? 0 : 0x7fff, cdrom_muted ? 0 : 0x7fff);
                                break;
                        case 0x0110: // do_play!
-                               sys_command_cd_volume (DF_IOCTL, unitnum, cdrom_muted ? 0 : 0xffff);
+                               sys_command_cd_volume (unitnum, cdrom_muted ? 0 : 0x7fff, cdrom_muted ? 0 : 0x7fff);
                                cdaudioplay_do ();
                                break;
                        }
@@ -1327,7 +1326,7 @@ static void *akiko_thread (void *null)
 
                if (frame2counter <= 0) {
                        frame2counter = 312 * 50 / 2;
-                       if (sys_command_cd_qcode (DF_IOCTL, unitnum, qcode_buf)) {
+                       if (unitnum >= 0 && sys_command_cd_qcode (unitnum, qcode_buf)) {
                                uae_u8 as = qcode_buf[1];
                                qcode_valid = 1;
                                if (as == AUDIO_STATUS_IN_PROGRESS) {
@@ -1343,14 +1342,14 @@ static void *akiko_thread (void *null)
 
                if (mediacheckcounter <= 0) {
                        mediacheckcounter = 312 * 50 * 2;
-                       int media = sys_command_ismedia (DF_IOCTL, unitnum, 1);
+                       int media = sys_command_ismedia (unitnum, 1);
                        if (media < 0) {
                                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 ();
+                                       cd_hunt = 1;
                                }
                        } else if (media != lastmediastate) {
                                write_log (L"CD32: media changed = %d (hunt=%d)\n", media, cd_hunt);
@@ -1375,12 +1374,10 @@ static void *akiko_thread (void *null)
                                sector_buffer_sector_2 = sector;
                                offset = 0;
                                while (offset < SECTOR_BUFFER_SIZE) {
-                                       p = 0;
+                                       int ok = 0;
                                        if (sector < cdrom_data_end)
-                                               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;
+                                               ok = sys_command_cd_read (unitnum, sector_buffer_2 + offset * 2048, sector, 1);
+                                       sector_buffer_info_2[offset] = ok ? 3 : 0;
                                        offset++;
                                        sector++;
                                }
@@ -1767,7 +1764,7 @@ int akiko_init (void)
 {
        if (currprefs.cs_cd32cd && cdromok == 0) {
                unitnum = -1;
-               if (!device_func_init (DEVICE_TYPE_IOCTL)) {
+               if (!device_func_init (0)) {
                        write_log (L"no CDROM support\n");
                        return 0;
                }
index 5369750e9764f0f24fdbbd6c2e3165af6c0b22da..1b34842e7392a64bf53f9e6fa7576caae199fb9d 100644 (file)
 #include "blkdev.h"
 #include "scsidev.h"
 #include "savestate.h"
+#ifdef RETROPLATFORM
+#include "rp.h"
+#endif
 
-static int scsiemu;
+static int scsiemu[MAX_TOTAL_SCSI_DEVICES];
 
-static struct device_functions *device_func[2];
-static int have_ioctl;
-static int openlist[MAX_TOTAL_DEVICES];
-static int forcedunit = -1;
+static struct device_functions *device_func[MAX_TOTAL_SCSI_DEVICES];
+static int openlist[MAX_TOTAL_SCSI_DEVICES];
 
 /* convert minutes, seconds and frames -> logical sector number */
 int msf2lsn (int msf)
@@ -59,6 +60,34 @@ void tolongbcd (uae_u8 *p, int v)
        p[2] = tobcd ((v >> 0) & 0xff);
 }
 
+static struct cd_toc *gettoc (struct cd_toc_head *th, int block)
+{
+       for (int i = th->first_track_offset; i < th->last_track_offset; i++) {
+               struct cd_toc *t = &th->toc[i];
+               if (block < t->paddress) {
+                       if (i == th->first_track_offset)
+                               return t;
+                       else
+                               return t - 1;
+               }
+       }
+       return &th->toc[th->last_track_offset];
+}
+
+int isaudiotrack (struct cd_toc_head *th, int block)
+{
+       struct cd_toc *t = gettoc (th, block);
+       if (!t)
+               return 0;
+       return (t->control & 0x0c) != 4;
+}
+int isdatatrack (struct cd_toc_head *th, int block)
+{
+       return !isaudiotrack (th, block);
+}
+
+static int cdscsidevicetype[MAX_TOTAL_SCSI_DEVICES];
+
 #ifdef _WIN32
 
 #include "od-win32/win32.h"
@@ -68,173 +97,290 @@ extern struct device_functions devicefunc_win32_spti;
 extern struct device_functions devicefunc_win32_ioctl;
 extern struct device_functions devicefunc_cdimage;
 
+static struct device_functions *devicetable[] = {
+       NULL,
+       &devicefunc_cdimage,
+       &devicefunc_win32_ioctl,
+       &devicefunc_win32_spti,
+       &devicefunc_win32_aspi,
+       NULL
+};
+static int driver_installed[6];
+
 static void install_driver (int flags)
 {
-       scsiemu = 0;
-       device_func[DF_IOCTL] = NULL;
-       device_func[DF_SCSI] = NULL;
-       if (devicefunc_cdimage.checkbus (flags | DEVICE_TYPE_CHECKAVAIL)) {
-               device_func[DF_IOCTL] = &devicefunc_cdimage;
-               device_func[DF_SCSI] = &devicefunc_cdimage;
-               scsiemu = 1;
-               return;
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               scsiemu[i] = false;
+               device_func[i] = NULL;
+               switch (cdscsidevicetype[i])
+               {
+                       case SCSI_UNIT_IMAGE:
+                       device_func[i] = devicetable[SCSI_UNIT_IMAGE];
+                       scsiemu[i] = true;
+                       break;
+                       case SCSI_UNIT_IOCTL:
+                       device_func[i] = devicetable[SCSI_UNIT_IOCTL];
+                       scsiemu[i] = true;
+                       break;
+                       case SCSI_UNIT_SPTI:
+                       if (currprefs.win32_uaescsimode == UAESCSI_CDEMU) {
+                               device_func[i] = devicetable[SCSI_UNIT_IOCTL];
+                               scsiemu[i] = true;
+                       } else {
+                               device_func[i] = devicetable[SCSI_UNIT_SPTI];
+                       }
+                       break;
+                       case SCSI_UNIT_ASPI:
+                       device_func[i] = devicetable[SCSI_UNIT_ASPI];
+                       break;
+               }
        }
-#ifdef WINDDK
-       if (!device_func[DF_IOCTL])
-               device_func[DF_IOCTL] = &devicefunc_win32_ioctl;
-       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;
+
+       for (int j = 1; devicetable[j]; j++) {
+               if (!driver_installed[j]) {
+                       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+                               if (device_func[i] == devicetable[j]) {
+                                       int ok = device_func[i]->openbus (0);
+                                       driver_installed[j] = 1;
+                                       write_log (L"%s driver installed, ok=%d\n", device_func[i]->name, ok);
+                                       break;
+                               }
+                       }
                }
        }
-#endif
-       if (device_func[DF_SCSI])
-               device_func[DF_SCSI]->checkbus (DEVICE_TYPE_CHECKAVAIL);
-       if (device_func[DF_IOCTL])
-               device_func[DF_IOCTL]->checkbus (DEVICE_TYPE_CHECKAVAIL);
+
 }
 #endif
 
-int sys_command_isopen (int unitnum)
+void blkdev_default_prefs (struct uae_prefs *p)
 {
-       return openlist[unitnum];
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               p->cdimagefile[i][0] = 0;
+               p->cdimagefileuse[i] = false;
+               p->cdscsidevicetype[i] = SCSI_UNIT_NONE;
+               cdscsidevicetype[i] = SCSI_UNIT_NONE;
+       }
 }
 
-void sys_command_setunit (int unitnum)
+void blkdev_fix_prefs (struct uae_prefs *p)
 {
-       forcedunit = unitnum;
-}
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
+               cdscsidevicetype[i] = p->cdscsidevicetype[i];
 
-int sys_command_open (int mode, int unitnum)
-{
-       int ret = 0;
+       // blkdev_win32_aspi.cpp does not support multi units
+       if (currprefs.win32_uaescsimode >= UAESCSI_ASPI_FIRST) {
+               for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
+                       cdscsidevicetype[i] = SCSI_UNIT_ASPI;
+               return;
+       }
 
-       if (forcedunit >= 0) {
-               if (unitnum != forcedunit)
-                       return 0;
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (cdscsidevicetype[i] != SCSI_UNIT_NONE)
+                       continue;
+               if (p->cdimagefileuse[i] || p->cdimagefile[i][0]) {
+                       TCHAR *name = p->cdimagefile[i];
+                       if (_tcslen (name) == 3 && name[1] == ':' && name[2] == '\\') {
+                               if (currprefs.scsi && (currprefs.win32_uaescsimode == UAESCSI_SPTI || currprefs.win32_uaescsimode == UAESCSI_SPTISCAN))
+                                       cdscsidevicetype[i] = SCSI_UNIT_SPTI;
+                               else
+                                       cdscsidevicetype[i] = SCSI_UNIT_IOCTL;
+                       } else {
+                               cdscsidevicetype[i] = SCSI_UNIT_IMAGE;
+                       }
+               } else if (currprefs.scsi) {
+                       if (currprefs.win32_uaescsimode == UAESCSI_CDEMU)
+                               cdscsidevicetype[i] = SCSI_UNIT_IOCTL;
+                       else if (currprefs.win32_uaescsimode >= UAESCSI_ASPI_FIRST)
+                               cdscsidevicetype[i] = SCSI_UNIT_ASPI;
+                       else
+                               cdscsidevicetype[i] = SCSI_UNIT_SPTI;
+               } else {
+                       cdscsidevicetype[i] = SCSI_UNIT_IOCTL;
+               }
        }
 
-       if (mode == DF_SCSI || !have_ioctl) {
-               if (device_func[DF_SCSI] != NULL)
-                       ret = device_func[DF_SCSI]->opendev (unitnum);
-       } else {
-               ret = device_func[DF_IOCTL]->opendev (unitnum);
+}
+
+
+int sys_command_isopen (int unitnum)
+{
+       return openlist[unitnum];
+}
+
+int sys_command_open (int unitnum)
+{
+       int ret = 0;
+       if (openlist[unitnum])
+               write_log (L"BUG unit %d open: opencnt=%d!\n", unitnum, openlist[unitnum]);
+       if (device_func[unitnum]) {
+               ret = device_func[unitnum]->opendev (unitnum, currprefs.cdimagefile[unitnum][0] ? currprefs.cdimagefile[unitnum] : NULL);
+               if (ret)
+                       openlist[unitnum]++;
        }
-       if (ret)
-               openlist[unitnum]++;
        return ret;
 }
 
-void sys_command_close (int mode, int unitnum)
+void sys_command_close (int unitnum)
 {
-       if (mode == DF_SCSI || !have_ioctl) {
-               if (device_func[DF_SCSI] != NULL)
-                       device_func[DF_SCSI]->closedev (unitnum);
-       } else {
-               device_func[DF_IOCTL]->closedev (unitnum);
+       if (openlist[unitnum] <= 0)
+               write_log (L"BUG unit %d close: opencnt=%d!\n", unitnum, openlist[unitnum]);
+       if (device_func[unitnum]) {
+               device_func[unitnum]->closedev (unitnum);
+               if (openlist[unitnum] > 0)
+                       openlist[unitnum]--;
        }
-       if (openlist[unitnum] > 0)
-               openlist[unitnum]--;
 }
 
 void device_func_reset (void)
 {
-       have_ioctl = 0;
 }
 
 int device_func_init (int flags)
 {
-       static int old_flags = -1;
-       int support_scsi = 0, support_ioctl = 0;
-       int oflags;
-       
-       if (flags & DEVICE_TYPE_USE_OLD) {
-               if (old_flags >= 0)
-                       flags = old_flags;
-               else
-                       flags &= ~DEVICE_TYPE_USE_OLD;
+       device_func_reset ();
+       blkdev_fix_prefs (&currprefs);
+       install_driver (flags);
+       return 1;
+}
+
+static TCHAR newimagefiles[MAX_TOTAL_SCSI_DEVICES][256];
+static int imagechangetime[MAX_TOTAL_SCSI_DEVICES];
+static bool cdimagefileinuse[MAX_TOTAL_SCSI_DEVICES], wasopen[MAX_TOTAL_SCSI_DEVICES];
+
+static void check_changes (int unitnum)
+{
+       bool changed = false;
+
+       if (_tcscmp (changed_prefs.cdimagefile[unitnum], currprefs.cdimagefile[unitnum]) != 0)
+               changed = true;
+       if (!changed && changed_prefs.cdimagefile[unitnum][0] == 0 && changed_prefs.cdimagefileuse[unitnum] != currprefs.cdimagefileuse[unitnum])
+               changed = true;
+
+       if (changed) {
+               cdimagefileinuse[unitnum] = changed_prefs.cdimagefileuse[unitnum];
+               _tcscpy (newimagefiles[unitnum], changed_prefs.cdimagefile[unitnum]);
+               changed_prefs.cdimagefile[unitnum][0] = currprefs.cdimagefile[unitnum][0] = 0;
+               currprefs.cdimagefileuse[unitnum] = changed_prefs.cdimagefileuse[unitnum];
+               int pollmode = 0;
+               imagechangetime[unitnum] = 3 * 50;
+               struct device_info di;
+               device_func[unitnum]->info (unitnum, &di, 0);
+               wasopen[unitnum] = di.open;
+               if (wasopen[unitnum]) {
+                       device_func[unitnum]->closedev (unitnum);
+                       if (currprefs.scsi)  {
+                               scsi_do_disk_change (unitnum, 0, &pollmode);
+                               if (pollmode)
+                                       imagechangetime[unitnum] = 8 * 50;
+                       }
+               }
+               write_log (L"CD: eject (%s)\n", pollmode ? L"slow" : L"fast");
+#ifdef RETROPLATFORM
+               rp_cd_image_change (unitnum, NULL); 
+#endif
+       }
+       if (imagechangetime[unitnum] == 0)
+               return;
+       imagechangetime[unitnum]--;
+       if (imagechangetime[unitnum] > 0)
+               return;
+       _tcscpy (currprefs.cdimagefile[unitnum], newimagefiles[unitnum]);
+       _tcscpy (changed_prefs.cdimagefile[unitnum], newimagefiles[unitnum]);
+       currprefs.cdimagefileuse[unitnum] = changed_prefs.cdimagefileuse[unitnum] = cdimagefileinuse[unitnum];
+       newimagefiles[unitnum][0] = 0;
+       write_log (L"CD: delayed insert '%s'\n", currprefs.cdimagefile[unitnum][0] ? currprefs.cdimagefile[unitnum] : L"<EMPTY>");
+       device_func_init (0);
+       if (wasopen[unitnum]) {
+               if (!device_func[unitnum]->opendev (unitnum, currprefs.cdimagefile[unitnum])) {
+                       write_log (L"-> device open failed\n");
+               }
+       }
+       wasopen[unitnum] = 0;
+       if (currprefs.scsi) {
+               struct device_info di;
+               device_func[unitnum]->info (unitnum, &di, 0);
+               int pollmode;
+               scsi_do_disk_change (unitnum, 1, &pollmode);
        }
+#ifdef RETROPLATFORM
+       rp_cd_image_change (unitnum, currprefs.cdimagefile[unitnum]);
+#endif
+       config_changed = 1;
 
-       old_flags = flags;
+}
 
-       oflags = (flags & DEVICE_TYPE_SCSI) ? 0 : (1 << INQ_ROMD);
+void blkdev_vsync (void)
+{
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
+               check_changes (i);
+}
 
-       forcedunit = -1;
-       install_driver (flags);
-       if (device_func[DF_IOCTL])
-               have_ioctl = 1;
-       else
-               have_ioctl = 0;
-       if (flags & DEVICE_TYPE_ALLOWEMU)
-               oflags |= DEVICE_TYPE_ALLOWEMU;
-       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;
-       write_log (L"support_scsi = %d support_ioctl = %d\n", support_scsi, support_ioctl);
-       return (support_scsi ? (1 << DF_SCSI) : 0) | (support_ioctl ? (1 << DF_IOCTL) : 0);
+static int do_scsi (int unitnum, uae_u8 *cmd, int cmdlen)
+{
+       return 0;
+}
+static int do_scsi (int unitnum, uae_u8 *cmd, int cmdlen, uae_u8 *out, int outsize)
+{
+       return 0;
+}
+
+static int failunit (int unitnum)
+{
+       if (unitnum < 0 || unitnum >= MAX_TOTAL_SCSI_DEVICES)
+               return 1;
+       if (device_func[unitnum] == NULL)
+               return 1;
+       return 0;
 }
 
 static int audiostatus (int unitnum)
 {
        uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,(uae_u8)(DEVICE_SCSI_BUFSIZE>>8),(uae_u8)(DEVICE_SCSI_BUFSIZE&0xff),0};
-       uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+       uae_u8 *p = device_func[unitnum]->exec_in (unitnum, cmd, sizeof (cmd), 0);
        if (!p)
                return 0;
        return p[1];
 }
 
 /* pause/unpause CD audio */
-void sys_command_cd_pause (int mode, int unitnum, int paused)
+int sys_command_cd_pause (int unitnum, int paused)
 {
-       if (mode == DF_SCSI || !have_ioctl) {
+       if (failunit (unitnum))
+               return -1;
+       if (device_func[unitnum]->pause == NULL) {
                int as = audiostatus (unitnum);
-               if ((paused && as == 0x11) && (!paused && as == 0x12)) {
-                       uae_u8 cmd[10] = {0x4b,0,0,0,0,0,0,0,paused?0:1,0};
-                       device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd));
-               }
-               return;
+               uae_u8 cmd[10] = {0x4b,0,0,0,0,0,0,0,paused?0:1,0};
+               do_scsi (unitnum, cmd, sizeof cmd);
+               return as == AUDIO_STATUS_PAUSED;
        }
-       device_func[DF_IOCTL]->pause (unitnum, paused);
+       return device_func[unitnum]->pause (unitnum, paused);
 }
 
 /* stop CD audio */
-void sys_command_cd_stop (int mode, int unitnum)
+void sys_command_cd_stop (int unitnum)
 {
-       if (mode == DF_SCSI || !have_ioctl) {
+       if (failunit (unitnum))
+               return;
+       if (device_func[unitnum]->stop == NULL) {
                int as = audiostatus (unitnum);
-               if (as == 0x11) {
-                       uae_u8 cmd[6] = {0x4e,0,0,0,0,0};
-                       device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd));
-               }
+               uae_u8 cmd[6] = {0x4e,0,0,0,0,0};
+               do_scsi (unitnum, cmd, sizeof cmd);
                return;
        }
-       device_func[DF_IOCTL]->stop (unitnum);
+       device_func[unitnum]->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))
+       if (!device_func[unitnum]->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))
+               if (!device_func[unitnum]->qcode (unitnum, q, startlsn - 1))
                        break;
                int track = frombcd (q[4 + 1]);
                int idx = frombcd (q[4 + 2]);
@@ -253,179 +399,154 @@ static int adjustplaypos (int unitnum, int startlsn)
 #endif
 
 /* play CD audio */
-int sys_command_cd_play (int mode, int unitnum, int startlsn, int endlsn, int scan)
+int sys_command_cd_play (int unitnum, int startlsn, int endlsn, int scan)
 {
-       if (mode == DF_SCSI || !have_ioctl) {
+       if (failunit (unitnum))
+               return 0;
+       if (device_func[unitnum]->play == NULL) {
                uae_u8 cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
-#if 0
-               if (scan) {
-                       cmd[0] = 0xba;
-                       cmd[1] = scan < 0 ? 0x10 : 0x0;
-                       cmd[3] = (uae_u8)(startmsf >> 16);
-                       cmd[4] = (uae_u8)(startmsf >> 8);
-                       cmd[5] = (uae_u8)(startmsf >> 0);
-                       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);
-                       cmd[5] = (uae_u8)(startmsf >> 0);
-                       cmd[6] = (uae_u8)(endmsf >> 16);
-                       cmd[7] = (uae_u8)(endmsf >> 8);
-                       cmd[8] = (uae_u8)(endmsf >> 0);
-#if 0
-               }
-#endif
-               return device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd)) == 0 ? 0 : 1;
+               int startmsf = lsn2msf (startlsn);
+               int endmsf = lsn2msf (endlsn);
+               cmd[0] = 0x47;
+               cmd[3] = (uae_u8)(startmsf >> 16);
+               cmd[4] = (uae_u8)(startmsf >> 8);
+               cmd[5] = (uae_u8)(startmsf >> 0);
+               cmd[6] = (uae_u8)(endmsf >> 16);
+               cmd[7] = (uae_u8)(endmsf >> 8);
+               cmd[8] = (uae_u8)(endmsf >> 0);
+               return do_scsi (unitnum, cmd, sizeof cmd) ? 0 : 1;
        }
        //startlsn = adjustplaypos (unitnum, startlsn);
-       return device_func[DF_IOCTL]->play (unitnum, startlsn, endlsn, scan, NULL);
+       return device_func[unitnum]->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)
+int sys_command_cd_play (int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc)
 {
-       if (mode == DF_SCSI || !have_ioctl)
+       if (failunit (unitnum))
                return 0;
+       if (device_func[unitnum]->play == NULL)
+               return sys_command_cd_play (unitnum, startlsn, endlsn, scan);
        //startlsn = adjustplaypos (unitnum, startlsn);
-       return device_func[DF_IOCTL]->play (unitnum, startlsn, endlsn, scan, subfunc);
+       return device_func[unitnum]->play (unitnum, startlsn, endlsn, scan, subfunc);
 }
 
 /* set CD audio volume */
-void sys_command_cd_volume (int mode, int unitnum, uae_u16 volume)
+uae_u32 sys_command_cd_volume (int unitnum, uae_u16 volume_left, uae_u16 volume_right)
 {
-       if (mode == DF_SCSI || !have_ioctl)
-               return;
-       device_func[DF_IOCTL]->volume (unitnum, volume);
+       if (failunit (unitnum))
+               return 0;
+       if (device_func[unitnum]->volume == NULL)
+               return -1;
+       return device_func[unitnum]->volume (unitnum, volume_left, volume_right);
 }
 
 /* read qcode */
-int sys_command_cd_qcode (int mode, int unitnum, uae_u8 *buf)
+int sys_command_cd_qcode (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};
-               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; 
+       if (failunit (unitnum))
+               return 0;
+       if (device_func[unitnum]->qcode == NULL) {
+               uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,(uae_u8)(SUBQ_SIZE>>8),(uae_u8)(SUBQ_SIZE&0xff),0};
+               return do_scsi (unitnum, cmd, sizeof cmd, buf, SUBQ_SIZE);
        }
-       return device_func[DF_IOCTL]->qcode (unitnum, buf, -1);
+       return device_func[unitnum]->qcode (unitnum, buf, -1);
 };
 
 /* read table of contents */
-struct cd_toc_head *sys_command_cd_toc (int mode, int unitnum)
+int sys_command_cd_toc (int unitnum, struct cd_toc_head *toc)
 {
-       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 NULL;
-//             return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof(cmd), 0);
+       if (failunit (unitnum))
+               return 0;
+       if (device_func[unitnum]->toc == NULL) {
+               uae_u8 buf[4 + 8 * 103];
+               int size = sizeof buf;
+               uae_u8 cmd [10] = { 0x43,0,2,0,0,0,0,(uae_u8)(size>>8),(uae_u8)(size&0xff),0};
+               if (do_scsi (unitnum, cmd, sizeof cmd, buf, size)) {
+                       // toc parse to do
+                       return 0;
+               }
+               return 0;
        }
-       return device_func[DF_IOCTL]->toc (unitnum);
+       return device_func[unitnum]->toc (unitnum, toc);
 }
 
 /* read one cd sector */
-uae_u8 *sys_command_cd_read (int mode, int unitnum, uae_u8 *data, int block, int size)
+int sys_command_cd_read (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)(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;
+       if (failunit (unitnum))
+               return 0;
+       if (device_func[unitnum]->read == NULL) {
+               uae_u8 cmd[12] = { 0xbe, 0, block >> 24, block >> 16, block >> 8, block >> 0, size >> 16, size >> 8, size >> 0, 0x10, 0, 0 };
+               cmd[1] = 2 << 3; // 2048
+               if (!do_scsi (unitnum, cmd, sizeof cmd, data, size * 2048))
+                       cmd[1] = 4 << 3; // 2048 mode2
+               return do_scsi (unitnum, cmd, sizeof cmd, data, size * 2048);
        }
-       return device_func[DF_IOCTL]->read (unitnum, data, block, size);
+       return device_func[unitnum]->read (unitnum, data, block, size);
 }
-uae_u8 *sys_command_cd_rawread (int mode, int unitnum, uae_u8 *data, int sector, int size, int sectorsize)
+int sys_command_cd_rawread (int unitnum, uae_u8 *data, int block, int size, int sectorsize)
 {
-       if (mode == DF_SCSI || !have_ioctl) {
-               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;
+       if (failunit (unitnum))
+               return -1;
+       if (device_func[unitnum]->rawread == NULL) {
+               uae_u8 cmd[12] = { 0xbe, 0, block >> 24, block >> 16, block >> 8, block >> 0, size >> 16, size >> 8, size >> 0, 0x10, 0, 0 };
+               return do_scsi (unitnum, cmd, sizeof cmd, data, size * sectorsize);
        }
-       return device_func[DF_IOCTL]->rawread (unitnum, data, sector, size, sectorsize);
+       return device_func[unitnum]->rawread (unitnum, data, block, size, sectorsize, 0xffff);
+}
+int sys_command_cd_rawread (int unitnum, uae_u8 *data, int block, int size, int sectorsize, uae_u8 scsicmd9, uae_u8 subs)
+{
+       if (failunit (unitnum))
+               return -1;
+       if (device_func[unitnum]->rawread == NULL) {
+               uae_u8 cmd[12] = { 0xbe, 0, block >> 24, block >> 16, block >> 8, block >> 0, size >> 16, size >> 8, size >> 0, 0x10, 0, 0 };
+               return do_scsi (unitnum, cmd, sizeof cmd, data, size * sectorsize);
+       }
+       return device_func[unitnum]->rawread (unitnum, data, block, size, sectorsize, (scsicmd9 << 8) | subs);
 }
 
 /* read block */
-uae_u8 *sys_command_read (int mode, int unitnum, uae_u8 *data, int block, int size)
+int sys_command_read (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 };
+       if (failunit (unitnum))
+               return 0;
+       if (device_func[unitnum]->read == NULL) {
+               uae_u8 cmd[12] = { 0xa8, 0, 0, 0, 0, 0, size >> 24, size >> 16, size >> 8, size >> 0, 0, 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 do_scsi (unitnum, cmd, sizeof cmd, data, size * 2048);
        }
-       return device_func[DF_IOCTL]->read (unitnum, data, block, size);
+       return device_func[unitnum]->read (unitnum, data, block, size);
 }
 
 /* write block */
-int sys_command_write (int mode, int unitnum, uae_u8 *data, int offset, int size)
+int sys_command_write (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, size, 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);
-               if (device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0))
-                       return -1;
+       if (failunit (unitnum))
                return 0;
-       }
-       return device_func[DF_IOCTL]->write (unitnum, data, offset, size);
+       if (device_func[unitnum]->write == NULL)
+               return 0;
+       return device_func[unitnum]->write (unitnum, data, offset, size);
 }
 
-int sys_command_ismedia (int mode, int unitnum, int quick)
+int sys_command_ismedia (int unitnum, int quick)
 {
-       struct device_info di;
-
-       if (forcedunit >= 0) {
-               if (unitnum != forcedunit)
-                       return -1;
-       }
-
-       if (mode == DF_SCSI || !have_ioctl || !device_func[DF_IOCTL]->ismedia) {
-               if (quick)
-                       return -1;
-               memset(&di, 0, sizeof di);
-               if (device_func[DF_SCSI]->info (unitnum, &di, quick) == NULL, quick)
-                       return -1;
-               return di.media_inserted;
+       if (failunit (unitnum))
+               return -1;
+       if (device_func[unitnum] == NULL) {
+               uae_u8 cmd[6] = { 0, 0, 0, 0, 0, 0 };
+               return do_scsi (unitnum, cmd, sizeof cmd);
        } else {
-               return device_func[DF_IOCTL]->ismedia (unitnum, quick);
+               return device_func[unitnum]->ismedia (unitnum, quick);
        }
 }
 
-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, quick);
-       else
-               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)
+struct device_info *sys_command_info (int unitnum, struct device_info *di, int quick)
 {
-       if (mode == DF_SCSI || !have_ioctl)
-               return device_func[DF_SCSI]->scsiinfo (unitnum, dsi);
-       else
-               return device_func[DF_IOCTL]->scsiinfo (unitnum, dsi);
+       return device_func[unitnum]->info (unitnum, di, quick);
 }
 
 #define MODE_SELECT_6 0x15
@@ -561,7 +682,10 @@ uae_u8 *save_cd (int num, int *len)
 
        dstbak = dst = xmalloc (uae_u8, 4 + 256);
        save_u32 (4);
-       save_string (currprefs.cdimagefile);
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               save_string (currprefs.cdimagefile[i]);
+               save_u32 (currprefs.cdscsidevicetype[i]);
+       }
        *len = dst - dstbak;
        return dstbak;
 }
@@ -574,8 +698,8 @@ uae_u8 *restore_cd (int unit, uae_u8 *src)
        flags = restore_u32 ();
        s = restore_string ();
        if ((flags & 4) && unit == 0) {
-               _tcscpy (changed_prefs.cdimagefile, s);
-               _tcscpy (currprefs.cdimagefile, s);
+               _tcscpy (changed_prefs.cdimagefile[0], s);
+               _tcscpy (currprefs.cdimagefile[0], s);
        }
        return src;
 }
@@ -586,7 +710,7 @@ static bool nodisk (struct device_info *di)
 }
 static uae_u64 cmd_readx (int unitnum, uae_u8 *dataptr, int offset, int len)
 {
-       if (device_func[DF_IOCTL]->read (unitnum, dataptr, offset, len))
+       if (device_func[unitnum]->read (unitnum, dataptr, offset, len))
                return len;
        else
                return 0;
@@ -608,18 +732,66 @@ static int rl (uae_u8 *p)
 {
        return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
 }
+static int rw (uae_u8 *p)
+{
+       return (p[0] << 8) | (p[1]);
+}
 
-static struct cd_toc *gettoc (struct device_info *di, int block)
+static void stopplay (int unitnum)
 {
-       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;
+       sys_command_cd_stop (unitnum);
+}
+
+static int addtocentry (uae_u8 **dstp, int *len, int point, int newpoint, int msf, uae_u8 *head, struct cd_toc_head *th)
+{
+       uae_u8 *dst = *dstp;
+
+       for (int i = 0; i < th->points; i++) {
+               struct cd_toc *t = &th->toc[i];
+               if (t->point == point) {
+                       if (*len < 8)
+                               return 0;
+                       int addr = t->paddress;
+                       if (msf)
+                               addr = lsn2msf (addr);
+                       dst[0] = 0;
+                       dst[1] = (t->adr << 4) | t->control;
+                       dst[2] = newpoint >= 0 ? newpoint : point;
+                       dst[3] = 0;
+                       dst[4] = addr >> 24;
+                       dst[5] = addr >> 16;
+                       dst[6] = addr >>  8;
+                       dst[7] = addr >>  0;
+
+                       if (point >= 1 && point <= 99) {
+                               if (head[2] == 0)
+                                       head[2] = point;
+                               head[3] = point;
+                       }
+
+                       *len -= 8;
+                       *dstp = dst + 8;
+                       return 1;
                }
        }
-       return &di->toc.toc[di->toc.last_track_offset];
+       return -1;
+}
+
+static int scsi_read_cd (int unitnum, uae_u8 *cmd, uae_u8 *data, struct device_info *di)
+{
+       int msf = cmd[0] == 0xb9;
+       int start = msf ? msf2lsn (rl (cmd + 2) & 0x00ffffff) : rl (cmd + 2);
+       int len = rl (cmd + 5) & 0x00ffffff;
+       if (msf) {
+               int end = msf2lsn (len);
+               len = end - start;
+               if (len < 0)
+                       return -1;
+       }
+       int subs = cmd[10] & 7;
+       if (len == 0)
+               return 0;
+       return sys_command_cd_rawread (unitnum, data, start, len, 0, cmd[9], subs);
 }
 
 static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
@@ -629,15 +801,13 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
        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);
+       sys_command_info (unitnum, &di, 1);
 
        if (cmdbuf[0] == 0) { /* TEST UNIT READY */
                if (nodisk (&di))
@@ -645,10 +815,14 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
                scsi_len = 0;
                goto end;
        }
-               
+       write_log (L"SCSIEMU %d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X CMDLEN=%d DATA=%08X LEN=%d\n", unitnum,
+               cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5], cmdbuf[6], 
+               cmdbuf[7], cmdbuf[8], cmdbuf[9], cmdbuf[10], cmdbuf[11],
+               scsi_cmd_len, scsi_data, *data_len);
        switch (cmdbuf[0])
        {
        case 0x12: /* INQUIRY */
+       {
                if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
                        goto err;
                len = cmdbuf[4];
@@ -663,98 +837,135 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
                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++;
+               char *s = ua (di.vendorid);
+               memcpy (r + 8, s, strlen (s));
+               xfree (s);
+               s = ua (di.productid);
+               memcpy (r + 16, s, strlen (s));
+               xfree (s);
+               s = ua (di.revision);
+               memcpy (r + 32, s, strlen (s));
+               xfree (s);
+               for (int i = 8; i < 36; i++) {
+                       if (r[i] == 0)
+                               r[i] = 32;
                }
+       }
+       break;
+       case 0xbe: // READ CD
+       case 0xb9: // READ CD MSF
+               if (nodisk (&di))
+                       goto nodisk;
+               scsi_len = scsi_read_cd (unitnum, cmdbuf, scsi_data, &di);
+               if (scsi_len == -2)
+                       goto notdatatrack;
+               if (scsi_len == -1)
+                       goto errreq;
                break;
+       case 0x55: // MODE SELECT(10)
+       case 0x15: // MODE SELECT(6)
+       {
+               uae_u8 *p;
+               p = scsi_data + 4;
+               if (cmdbuf[0] == 0x55)
+                       p += 4;
+               int pcode = p[0] & 0x3f;
+               if (pcode == 14) { // CD audio control
+                       uae_u16 vol_left = (p[9] << 7) | (p[9] >> 1);
+                       uae_u16 vol_right = (p[11] << 7) | (p[11] >> 1);
+                       sys_command_cd_volume (unitnum, vol_left, vol_right);
+                       scsi_len = 0;
+               } else {
+                       goto errreq;
+               }
+       }
+       break;
+       case 0x5a: // MODE SENSE(10)
        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;
+       {
+               uae_u8 *p;
+               int pc = cmdbuf[2] >> 6;
+               int pcode = cmdbuf[2] & 0x3f;
+               int dbd = cmdbuf[1] & 8;
+               if (cmdbuf[0] == 0x5a)
+                       dbd = 1;
+               write_log (L"MODE SENSE PC=%d CODE=%d DBD=%d\n", pc, pcode, dbd);
+               p = r;
+               if (cmdbuf[0] == 0x5a) {
+                       p[0] = 8 - 1;
+                       p[1] = 0;
+                       p[2] = 0;
+                       p[3] = 0;
+                       p[4] = 0;
+                       p[5] = 0;
+                       p[6] = 0;
+                       p[7] = 0;
+                       p += 8;
+               } else {
                        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;
+               if (!dbd) {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       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) {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       p[0] = 3;
+                       p[1] = 24;
+                       p[3] = 1;
+                       p[10] = di.trackspercylinder >> 8;
+                       p[11] = di.trackspercylinder;
+                       p[12] = di.bytespersector >> 8;
+                       p[13] = di.bytespersector;
+                       p[15] = 1; // interleave
+                       p[20] = 0x80;
+                       r[0] += p[1];
+               } else if (pcode == 4) {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       p[0] = 4;
+                       wl(p + 1, di.cylinders);
+                       p[1] = 24;
+                       p[5] = 1;
+                       wl(p + 13, di.cylinders);
+                       ww(p + 20, 0);
+                       r[0] += p[1];
+               } else if (pcode == 14) { // CD audio control
+                       uae_u32 vol = sys_command_cd_volume (unitnum, 0xffff, 0xffff);
+                       p[0] = 0x0e;
+                       p[1] = 0x0e;
+                       p[2] = 1;
+                       p[3] = 4;
+                       p[6] = 0;
+                       p[7] = 75;
+                       p[8] = 1;
+                       p[9] = pc == 0 ? (vol >> 7) & 0xff : 0xff;
+                       p[10] = 2;
+                       p[11] = pc == 0 ? (vol >> (16 + 7)) & 0xff : 0xff;
+                       r[0] += p[1];
+               } else {
+                       goto err;
+               }
+               r[0] += r[3];
+               scsi_len = lr = r[0] + 1;
+       }
+       break;
        case 0x1d: /* SEND DIAGNOSTICS */
                scsi_len = 0;
                break;
@@ -788,8 +999,9 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
        {
                if (nodisk (&di))
                        goto nodisk;
+               stopplay (unitnum);
                offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
-               struct cd_toc *t = gettoc (&di, offset);
+               struct cd_toc *t = gettoc (&di.toc, offset);
                if ((t->control & 0x0c) == 0x04) {
                        len = cmdbuf[4];
                        if (!len)
@@ -806,8 +1018,9 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
        {
                if (nodisk (&di))
                        goto nodisk;
+               stopplay (unitnum);
                offset = rl (cmdbuf + 2);
-               struct cd_toc *t = gettoc (&di, offset);
+               struct cd_toc *t = gettoc (&di.toc, offset);
                if ((t->control & 0x0c) == 0x04) {
                        len = rl (cmdbuf + 7 - 2) & 0xffff;
                        scsi_len = cmd_readx (unitnum, scsi_data, offset, len) * di.bytespersector;
@@ -822,8 +1035,9 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
        {
                if (nodisk (&di))
                        goto nodisk;
+               stopplay (unitnum);
                offset = rl (cmdbuf + 2);
-               struct cd_toc *t = gettoc (&di, offset);
+               struct cd_toc *t = gettoc (&di.toc, offset);
                if ((t->control & 0x0c) == 0x04) {
                        len = rl (cmdbuf + 6);
                        scsi_len = (uae_u32)cmd_readx (unitnum, scsi_data, offset, len) * di.bytespersector;;
@@ -836,57 +1050,231 @@ static int scsi_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
                goto readprot;
        case 0x43: // READ TOC
                {
+                       if (nodisk (&di))
+                               goto nodisk;
                        uae_u8 *p = scsi_data;
                        int strack = cmdbuf[6];
                        int msf = cmdbuf[1] & 2;
+                       int format = cmdbuf[2] & 7;
+                       if (format >= 3)
+                               goto errreq;
                        int maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
-                       struct cd_toc_head *toc = sys_command_cd_toc (DF_IOCTL, unitnum);
-                       if (!toc)
+                       struct cd_toc_head ttoc;
+                       if (!sys_command_cd_toc (unitnum, &ttoc))
                                goto readerr;
+                       struct cd_toc_head *toc = &ttoc;
                        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)
+                       if (format == 1) {
+                               p[0] = 0;
+                               p[1] = 8;
+                               p[2] = 1;
+                               p[3] = 1;
+                               p[4] = 0;
+                               p[5] = (toc->toc[0].adr << 4) | toc->toc[0].control;
+                               p[6] = toc->first_track;
+                               p[7] = 0;
+                               if (msf)
+                                       wl (p + 8, lsn2msf (toc->toc[0].address));
+                               else
+                                       wl (p + 8 , toc->toc[0].address);
+                               scsi_len = 12;
+                       } else if (format == 2 || format == 0) {
+                               if (format == 2 && !msf)
+                                       goto errreq;
+                               if (strack == 0)
+                                       strack = toc->first_track;
+                               if (format == 0 && strack >= 100 && strack != 0xaa)
+                                       goto errreq;
+                               uae_u8 *p2 = p + 4;
+                               p[2] = 0;
+                               p[3] = 0;
+                               maxlen -= 4;
+                               if (format == 2) {
+                                       if (!addtocentry (&p2, &maxlen, 0xa0, -1, msf, p, toc))
+                                               goto errreq;
+                                       if (!addtocentry (&p2, &maxlen, 0xa1, -1, msf, p, toc))
+                                               goto errreq;
+                                       if (!addtocentry (&p2, &maxlen, 0xa2, -1, msf, p, toc))
+                                               goto errreq;
+                               }
+                               while (strack < 100) {
+                                       if (!addtocentry (&p2, &maxlen, strack, -1, msf, p, toc))
                                                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;
+                               if (!addtocentry (&p2, &maxlen, 0xa2, 0xaa, msf, p, toc))
+                                       goto errreq;
+                               int tlen = p2 - (p + 4);
+                               p[0] = tlen >> 8;
+                               p[1] = tlen >> 0;
+                               scsi_len = tlen + 4;
+                       }
+               }
+               break;
+               case 0x42: // READ SUB-CHANNEL
+               {
+                       int msf = cmdbuf[1] & 2;
+                       int subq = cmdbuf[2] & 0x40;
+                       int format = cmdbuf[3];
+                       int track = cmdbuf[6];
+                       int len = rw (cmdbuf + 7);
+                       uae_u8 buf[SUBQ_SIZE] = { 0 };
+
+                       if (nodisk (&di))
+                               goto nodisk;
+                       sys_command_cd_qcode (unitnum, buf);
+                       if (len < 4)
+                               goto errreq;
+                       scsi_len = 4;
+                       scsi_data[0] = 0;
+                       scsi_data[1] = buf[1];
+                       if (subq && format == 1) {
+                               if (len < 4 + 12)
+                                       goto errreq;
+                               scsi_data[2] = 0;
+                               scsi_data[3] = 12;
+                               scsi_len += 12;
+                               scsi_data[4] = 1;
+                               scsi_data[5] = (buf[4 + 0] << 4) | (buf[4 + 0] >> 4);
+                               scsi_data[6] = frombcd (buf[4 + 1]); // track
+                               scsi_data[7] = frombcd (buf[4 + 2]); // index
+                               int reladdr = fromlongbcd (&buf[4 + 3]);
+                               int absaddr = fromlongbcd (&buf[4 + 7]);
+                               if (!msf) {
+                                       reladdr = msf2lsn (reladdr);
+                                       absaddr = msf2lsn (absaddr);
+                               }
+                               wl (scsi_data +  8, absaddr);
+                               wl (scsi_data + 12, reladdr);
+                       } else {
+                               scsi_data[2] = 0;
+                               scsi_data[3] = 0;
+                       }
+               }
+               break;
+               case 0x1b: // START/STOP
+                       sys_command_cd_stop (unitnum);
+                       scsi_len = 0;
+               break;
+               case 0x4e: // STOP PLAY/SCAN
+                       if (nodisk (&di))
+                               goto nodisk;
+                       sys_command_cd_stop (unitnum);
+                       scsi_len = 0;
+               break;
+               case 0xba: // SCAN
+               {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       struct cd_toc_head ttoc;
+                       if (!sys_command_cd_toc (unitnum, &ttoc))
+                               goto readerr;
+                       struct cd_toc_head *toc = &ttoc;
+                       int scan = (cmdbuf[1] & 0x10) ? -1 : 1;
+                       int start = rl (cmdbuf + 1) & 0x00ffffff;
+                       int end = scan > 0 ? toc->lastaddress : toc->toc[toc->first_track_offset].paddress;
+                       int type = cmdbuf[9] >> 6;
+                       if (type == 1)
+                               start = lsn2msf (start);
+                       if (type == 3)
+                               goto errreq;
+                       if (type == 2) {
+                               if (toc->first_track_offset + start >= toc->last_track_offset)
+                                       goto errreq;
+                               start = toc->toc[toc->first_track_offset + start].paddress;
+                       }
+                       sys_command_cd_play (unitnum, start, end, scan, NULL);
+                       scsi_len = 0;
+               }
+               break;
+               case 0x48: // PLAY AUDIO TRACK/INDEX
+               {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       int strack = cmdbuf[4];
+                       int etrack = cmdbuf[7];
+                       struct cd_toc_head ttoc;
+                       if (!sys_command_cd_toc (unitnum, &ttoc))
+                               goto readerr;
+                       struct cd_toc_head *toc = &ttoc;
+                       if (strack < toc->first_track || strack > toc->last_track ||
+                               etrack < toc->first_track || etrack > toc->last_track ||
+                               strack > etrack)
+                               goto errreq;
+                       int start = toc->toc[toc->first_track_offset + strack - 1].paddress;
+                       int end = etrack == toc->last_track ? toc->lastaddress : toc->toc[toc->first_track_offset + etrack - 1 + 1].paddress;
+                       if (!sys_command_cd_play (unitnum, start, end, 0, NULL))
+                               goto notdatatrack;
+                       scsi_len = 0;
+               }
+               break;
+               case 0x47: // PLAY AUDIO MSF
+               {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       int start = rl (cmdbuf + 2) & 0x00ffffff;
+                       if (start == 0x00ffffff) {
+                               uae_u8 buf[SUBQ_SIZE] = { 0 };
+                               sys_command_cd_qcode (unitnum, buf);
+                               start = fromlongbcd (buf + 4 + 7);
+                       }
+                       int end = msf2lsn (rl (cmdbuf + 5) & 0x00ffffff);
+                       start = msf2lsn (start);
+                       if (start > end)
+                               goto errreq;
+                       if (start < end)
+                               sys_command_cd_play (unitnum, start, end, 0, NULL);
+                       scsi_len = 0;
+               }
+               break;
+               case 0x45: // PLAY AUDIO
+               {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       int start = rl (cmdbuf + 2);
+                       int len = rw (cmdbuf + 7);
+                       if (len > 0) {
+                               if (start == -1) {
+                                       uae_u8 buf[SUBQ_SIZE] = { 0 };
+                                       sys_command_cd_qcode (unitnum, buf);
+                                       start = msf2lsn (fromlongbcd (buf + 4 + 7));
                                }
+                               sys_command_cd_play (unitnum, start, start + len, 0, NULL);
+                       }
+                       scsi_len = 0;
+               }
+               break;
+               case 0xbc: // PLAY CD
+               {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       int start = -1;
+                       int end = -1;
+                       if (cmdbuf[1] & 2) {
+                               start = msf2lsn (rl (cmdbuf + 2) & 0x00ffffff);
+                               end = msf2lsn (rl (cmdbuf + 5) & 0x00ffffff);
+                       } else {
+                               start = rl (cmdbuf + 2);
+                               end = start + rl (cmdbuf + 6);
                        }
-                       int tlen = p2 - (p + 4);
-                       p[0] = tlen >> 8;
-                       p[1] = tlen >> 0;
-                       scsi_len = tlen + 4;
+                       if (start > end)
+                               goto errreq;
+                       if (start < end)
+                               sys_command_cd_play (unitnum, start, end, 0, NULL);
+               }
+               break;
+               case 0x4b: // PAUSE/RESUME
+               {
+                       if (nodisk (&di))
+                               goto nodisk;
+                       uae_u8 buf[SUBQ_SIZE] = { 0 };
+                       int resume = cmdbuf[8] & 1;
+                       sys_command_cd_qcode (unitnum, buf);
+                       if (buf[1] != AUDIO_STATUS_IN_PROGRESS && buf[1] != AUDIO_STATUS_PAUSED)
+                               goto errreq;
+                       sys_command_cd_pause (unitnum, resume ? 0 : 1);
+                       scsi_len = 0;
                }
                break;
 readprot:
@@ -934,6 +1322,8 @@ end:
        *data_len = scsi_len;
        *reply_len = lr;
        *sense_len = ls;
+       if (cmdbuf[0])
+               write_log (L"-> DATAOUT=%d ST=%d SENSELEN=%d\n", scsi_len, status, ls);
        return status;
 }
 
@@ -943,7 +1333,7 @@ static int execscsicmd_direct (int unitnum, struct amigascsi *as)
        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 cmd[16] = { 0 };
        uae_u8 replydata[256];
        int datalen = as->len;
        int senselen = as->sense_len;
@@ -987,14 +1377,14 @@ static int execscsicmd_direct (int unitnum, struct amigascsi *as)
 
 int sys_command_scsi_direct_native (int unitnum, struct amigascsi *as)
 {
-       if (scsiemu) {
+       if (scsiemu[unitnum]) {
                return execscsicmd_direct (unitnum, as);
        } else {
-               if (!device_func[DF_SCSI] || !device_func[DF_SCSI]->exec_direct)
+               if (!device_func[unitnum]->exec_direct)
                        return -1;
        }
-       int ret = device_func[DF_SCSI]->exec_direct (unitnum, as);
-       if (!ret && device_func[DF_SCSI]->isatapi(unitnum))
+       int ret = device_func[unitnum]->exec_direct (unitnum, as);
+       if (!ret && device_func[unitnum]->isatapi(unitnum))
                scsi_atapi_fixup_inquiry (as);
        return ret;
 }
@@ -1018,6 +1408,8 @@ int sys_command_scsi_direct (int unitnum, uaecptr acmd)
        as.cmd_len = get_word (acmd + 16);
        for (i = 0; i < as.cmd_len; i++)
                as.cmd[i] = get_byte (ap++);
+       while (i < sizeof as.cmd)
+               as.cmd[i++] = 0;
        as.flags = get_byte (acmd + 20);
        as.sense_len = get_word (acmd + 26);
 
index 1d0396a0338cd8c1a8eaad62113e081db251fad0..8679a0443e1ee570149f3180c35bf20118d11548 100644 (file)
@@ -56,6 +56,7 @@ struct cdtoc
 
 struct cdunit {
        bool enabled;
+       bool open;
        uae_u8 buffer[2352];
        struct cdtoc toc[102];
        int tracks;
@@ -65,8 +66,8 @@ struct cdunit {
        int cdda_play_finished;
        int cdda_play;
        int cdda_paused;
-       int cdda_volume;
-       int cdda_volume_main;
+       int cdda_volume[2];
+       int cdda_scan;
        int cd_last_pos;
        int cdda_start, cdda_end;
        play_subchannel_callback cdda_subfunc;
@@ -75,9 +76,19 @@ struct cdunit {
        int donotmountme;
        TCHAR newfile[MAX_DPATH];
        uae_sem_t sub_sem;
+       struct device_info di;
 };
 
-static struct cdunit cdunits[MAX_TOTAL_DEVICES];
+static struct cdunit cdunits[MAX_TOTAL_SCSI_DEVICES];
+static int bus_open;
+
+static struct cdunit *unitisopen (int unitnum)
+{
+       struct cdunit *cdu = &cdunits[unitnum];
+       if (cdu->open)
+               return cdu;
+       return NULL;
+}
 
 static struct cdtoc *findtoc (struct cdunit *cdu, int *sectorp)
 {
@@ -164,9 +175,36 @@ static int getsub (uae_u8 *dst, struct cdunit *cdu, struct cdtoc *t, int sector)
        return ret;
 }
 
+static void sub_to_interleaved (const uae_u8 *s, uae_u8 *d)
+{
+       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++;
+       }
+}
+static void sub_to_deinterleaved (const 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++;
+       }
+}
+
 static void dosub (struct cdunit *cdu, struct cdtoc *t, int sector)
 {
-       uae_u8 *s, *d;
+       uae_u8 *d;
        uae_u8 subbuf[SUB_CHANNEL_SIZE];
        uae_u8 subbuf2[SUB_CHANNEL_SIZE];
 
@@ -181,36 +219,8 @@ static void dosub (struct cdunit *cdu, struct cdtoc *t, int sector)
        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
+               sub_to_interleaved (subbuf, subbuf2);
                d = subbuf2;
-
-
        } else {
                d = subbuf;
        }
@@ -229,10 +239,10 @@ static void *cdda_play_func (void *v)
        int i;
        WAVEHDR whdr[2];
        MMRESULT mmr;
-       int volume, volume_main;
+       int volume[2], volume_main;
        int oldplay;
        mp3decoder *mp3dec = NULL;
-       struct cdunit *cdu = &cdunits[0];
+       struct cdunit *cdu = (struct cdunit*)v;
        int firstloops;
 
        for (i = 0; i < 2; i++) {
@@ -250,7 +260,7 @@ static void *cdda_play_func (void *v)
        bufon[0] = bufon[1] = 0;
        bufnum = 0;
        buffered = 0;
-       volume = -1;
+       volume[0] = volume[1] = -1;
        volume_main = -1;
 
        if (cdda_openwav ()) {
@@ -294,6 +304,8 @@ static void *cdda_play_func (void *v)
                                        }
                                }
                                firstloops = 25;
+                               while (cdu->cdda_paused && cdu->cdda_play > 0)
+                                       Sleep (10);
                        }
 
                        while (!(whdr[bufnum].dwFlags & WHDR_DONE)) {
@@ -303,6 +315,9 @@ static void *cdda_play_func (void *v)
                        }
                        bufon[bufnum] = 0;
 
+                       if (!isaudiotrack (&cdu->di.toc, cdda_pos))
+                               goto end; // data track?
+
                        if ((cdda_pos < cdu->cdda_end || cdu->cdda_end == 0xffffffff) && !cdu->cdda_paused && cdu->cdda_play > 0) {
                                struct cdtoc *t;
                                int sector, cnt;
@@ -321,7 +336,13 @@ static void *cdda_play_func (void *v)
                                        for (cnt = 0; cnt < num_sectors; cnt++) {
                                                sector = cdda_pos;
 
-                                               cdda_pos++;
+                                               if (cdu->cdda_scan) {
+                                                       cdda_pos += cdu->cdda_scan;
+                                                       if (cdda_pos < 0)
+                                                               cdda_pos = 0;
+                                               } else  {
+                                                       cdda_pos++;
+                                               }
                                                if (cdda_pos - num_sectors < cdu->cdda_end && cdda_pos >= cdu->cdda_end)
                                                        dofinish = 1;
 
@@ -344,20 +365,22 @@ static void *cdda_play_func (void *v)
 
                                }
        
-                               volume = cdu->cdda_volume;
                                volume_main = currprefs.sound_volume;
-                               int vol_mult = (100 - volume_main) * volume / 100;
-                               if (vol_mult)
-                                       vol_mult++;
-                               if (vol_mult >= 65536)
-                                       vol_mult = 65536;
+                               int vol_mult[2];
+                               for (int j = 0; j < 2; j++) {
+                                       volume[j] = cdu->cdda_volume[j];
+                                       vol_mult[j] = (100 - volume_main) * volume[j] / 100;
+                                       if (vol_mult[j])
+                                               vol_mult[j]++;
+                                       if (vol_mult[j] >= 32768)
+                                               vol_mult[j] = 32768;
+                               }
                                uae_s16 *p = (uae_s16*)(px[bufnum]);
                                for (i = 0; i < num_sectors * 2352 / 4; i++) {
-                                       p[i * 2 + 0] = p[i * 2 + 0] * vol_mult / 65536;
-                                       p[i * 2 + 1] = p[i * 2 + 1] * vol_mult / 65536;
+                                       p[i * 2 + 0] = p[i * 2 + 0] * vol_mult[0] / 32768;
+                                       p[i * 2 + 1] = p[i * 2 + 1] * vol_mult[1] / 32768;
                                }
 
-
                                bufon[bufnum] = 1;
                                mmr = waveOutWrite (cdda_wavehandle, &whdr[bufnum], sizeof (WAVEHDR));
                                if (mmr != MMSYSERR_NOERROR) {
@@ -419,17 +442,18 @@ static void cdda_stop (struct cdunit *cdu)
 
 static int command_pause (int unitnum, int paused)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
-       if (unitnum)
-               return 0;
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return -1;
+       int old = cdu->cdda_paused;
        cdu->cdda_paused = paused;
-       return 1;
+       return old;
 }
 
 static int command_stop (int unitnum)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
-       if (unitnum)
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
                return 0;
        cdda_stop (cdu);
        return 1;
@@ -437,34 +461,35 @@ static int command_stop (int unitnum)
 
 static int command_play (int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
-       if (unitnum)
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return 0;
+       if (!isaudiotrack (&cdu->di.toc, startlsn))
                return 0;
-
-       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;
+       cdu->cdda_scan = scan > 0 ? 10 : (scan < 0 ? 10 : 0);
        if (!cdu->cdda_play)
-               uae_start_thread (L"cdda_play", cdda_play_func, NULL, NULL);
+               uae_start_thread (L"cdda_play", cdda_play_func, cdu, NULL);
        cdu->cdda_play++;
        return 1;
 }
 
 static int command_qcode (int unitnum, uae_u8 *buf, int sector)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return 0;
+
        uae_u8 subbuf[SUB_CHANNEL_SIZE];
        uae_u8 *p;
        int trk;
        int pos;
        int status;
 
-       if (unitnum)
-               return NULL;
-
        memset (buf, 0, SUBQ_SIZE);
        p = buf;
 
@@ -506,46 +531,89 @@ static int command_qcode (int unitnum, uae_u8 *buf, int sector)
        return 1;
 }
 
-static void command_volume (int unitnum, uae_u16 volume)
+static uae_u32 command_volume (int unitnum, uae_u16 volume_left, uae_u16 volume_right)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
-       cdu->cdda_volume = volume;
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return -1;
+       uae_u32 old = (cdu->cdda_volume[1] << 16) | (cdu->cdda_volume[0] << 0);
+       cdu->cdda_volume[0] = volume_left;
+       cdu->cdda_volume[1] = volume_right;
+       return old;
 }
 
-uae_u8 *command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize)
+static int command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize, uae_u16 extra)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
+       int ret = 0;
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return 0;
        struct cdtoc *t = findtoc (cdu, &sector);
        int offset;
 
-       if (unitnum)
-               return NULL;
        if (!t || t->handle == NULL)
-               return NULL;
-
+               return 0;
        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);
-       if (data)
+       if (sectorsize > 0) {
+               if (sectorsize > t->size)
+                       return 0;
+               offset = 0;
+               if (sectorsize == 2336 && t->size == 2352)
+                       offset = 16;
+               zfile_fseek (t->handle, t->offset + sector * t->size + offset, SEEK_SET);
                zfile_fread (data, sectorsize, size, t->handle);
-       else
-               zfile_fread (cdu->buffer, sectorsize, 1, t->handle);
-       cdu->cd_last_pos = sector;
-       return cdu->buffer;
+               cdu->cd_last_pos = sector;
+               ret = sectorsize * size;
+       } else {
+               uae_u8 cmd9 = extra >> 8;
+               int sync = (cmd9 >> 7) & 1;
+               int headercodes = (cmd9 >> 5) & 3;
+               int userdata = (cmd9 >> 4) & 1;
+               int edcecc = (cmd9 >> 3) & 1;
+               int errorfield = (cmd9 >> 1) & 3;
+               uae_u8 subs = extra & 7;
+               if (subs != 0 && subs != 1 && subs != 2 && subs != 4)
+                       return -1;
+
+               if (isaudiotrack (&cdu->di.toc, sector)) {
+                       if (t->size != 2352)
+                               return -2;
+                       for (int i = 0; i < size; i++) {
+                               zfile_fseek (t->handle, t->offset + sector * t->size, SEEK_SET);
+                               zfile_fread (data, t->size, 1, t->handle);
+                               uae_u8 *p = data + t->size;
+                               if (subs) {
+                                       uae_u8 subdata[SUB_CHANNEL_SIZE];
+                                       getsub (subdata, cdu, t, sector);
+                                       if (subs == 4) { // all, de-interleaved
+                                               memcpy (p, subdata, SUB_CHANNEL_SIZE);
+                                               p += SUB_CHANNEL_SIZE;
+                                       } else if (subs == 2) { // q-only
+                                               memcpy (p, subdata + SUB_ENTRY_SIZE, SUB_ENTRY_SIZE);
+                                               p += SUB_ENTRY_SIZE;
+                                       } else if (subs == 1) { // all, interleaved
+                                               sub_to_interleaved (subdata, p);
+                                               p += SUB_CHANNEL_SIZE;
+                                       }
+                               }
+                               ret += p - data;
+                               data = p;
+                               sector++;
+                       }
+               }
+       }
+       return ret;
 }
 
-static uae_u8 *command_read (int unitnum, uae_u8 *data, int sector, int size)
+static int command_read (int unitnum, uae_u8 *data, int sector, int size)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return 0;
+
        struct cdtoc *t = findtoc (cdu, &sector);
        int offset;
 
-       if (unitnum)
-               return NULL;
        if (!t || t->handle == NULL)
                return NULL;
        cdda_stop (cdu);
@@ -553,40 +621,37 @@ static uae_u8 *command_read (int unitnum, uae_u8 *data, int sector, int size)
        if (t->size > 2048)
                offset = 16;
        zfile_fseek (t->handle, t->offset + sector * t->size + offset, SEEK_SET);
-       if (data)
-               zfile_fread (data, size, 2048, t->handle);
-       else
-               zfile_fread (cdu->buffer, 2048, 1, t->handle);
+       zfile_fread (data, size, 2048, t->handle);
        cdu->cd_last_pos = sector;
-       return cdu->buffer;
+       return 1;
 }
 
-static struct cd_toc_head *command_toc (int unitnum)
+static int command_toc (int unitnum, struct cd_toc_head *th)
 {
-       struct cdunit *cdu = &cdunits[unitnum];
-       static struct cd_toc_head statictoc;
-       struct cd_toc *toc = &statictoc.toc[0];
+       struct cdunit *cdu = unitisopen (unitnum);
+       if (!cdu)
+               return 0;
+
        int i;
 
-       if (unitnum)
-               return NULL;
-       cdda_stop (cdu);
+       memset (&cdu->di.toc, 0, sizeof (struct cd_toc_head));
        if (!cdu->tracks)
-               return NULL;
+               return 0;
 
-       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;
+       memset (th, 0, sizeof (struct cd_toc_head));
+       struct cd_toc *toc = &th->toc[0];
+       th->first_track = 1;
+       th->last_track = cdu->tracks;
+       th->points = cdu->tracks + 3;
+       th->tracks = cdu->tracks;
+       th->lastaddress = cdu->toc[cdu->tracks].address;
 
        toc->adr = 1;
        toc->point = 0xa0;
-       toc->track = statictoc.first_track;
+       toc->track = th->first_track;
        toc++;
 
-       statictoc.first_track_offset = 1;
+       th->first_track_offset = 1;
        for (i = 0; i < cdu->tracks; i++) {
                toc->adr = cdu->toc[i].adr;
                toc->control = cdu->toc[i].ctrl;
@@ -596,19 +661,20 @@ static struct cd_toc_head *command_toc (int unitnum)
                toc++;
        }
 
-       statictoc.last_track_offset = cdu->tracks;
+       th->last_track_offset = cdu->tracks;
        toc->adr = 1;
        toc->point = 0xa1;
-       toc->track = statictoc.last_track;
+       toc->track = th->last_track;
        toc++;
 
        toc->adr = 1;
        toc->point = 0xa2;
-       toc->paddress = statictoc.lastaddress;
+       toc->paddress = th->lastaddress;
        toc++;
 
+       memcpy (&cdu->di.toc, th, sizeof (struct cd_toc_head));
        gui_flicker_led (LED_CD, unitnum, 1);
-       return &statictoc;
+       return 1;
 }
 
 static void skipspace (TCHAR **s)
@@ -653,7 +719,7 @@ static int readval (const TCHAR *s)
        return _tcstol (s, &endptr, base);
 }
 
-static int parseccd (struct cdunit *cdu, struct zfile *zcue, TCHAR *img)
+static int parseccd (struct cdunit *cdu, struct zfile *zcue, const TCHAR *img)
 {
        int mode;
        int num, tracknum, trackmode;
@@ -782,7 +848,7 @@ static int parseccd (struct cdunit *cdu, struct zfile *zcue, TCHAR *img)
        return cdu->tracks;
 }
 
-static int parsecue (struct cdunit *cdu, struct zfile *zcue, TCHAR *img)
+static int parsecue (struct cdunit *cdu, struct zfile *zcue, const TCHAR *img)
 {
        int tracknum, index0, pregap;
        int offset, secoffset, newfile;
@@ -1002,12 +1068,11 @@ static int parsecue (struct cdunit *cdu, struct zfile *zcue, TCHAR *img)
        return cdu->tracks;
 }
 
-static int parse_image (struct cdunit *cdu)
+static int parse_image (struct cdunit *cdu, const TCHAR *img)
 {
        struct zfile *zcue;
        int i;
-       TCHAR *img = currprefs.cdimagefile;
-       TCHAR *ext;
+       const TCHAR *ext;
        int secoffset;
 
        secoffset = 0;
@@ -1104,105 +1169,39 @@ static void unload_image (struct cdunit *cdu)
 }
 
 
-static int open_device (int unitnum)
+static int open_device (int unitnum, const TCHAR *ident)
 {
        struct cdunit *cdu = &cdunits[unitnum];
-       if (!cdu->enabled)
+
+       if (cdu->open)
                return 0;
        uae_sem_init (&cdu->sub_sem, 0, 1);
-       if (!cdu->tracks)
-               parse_image (cdu);
+       parse_image (cdu, ident);
+       cdu->open = true;
+       cdu->enabled = true;
+       cdu->cdda_volume[0] = 0x7fff;
+       cdu->cdda_volume[1] = 0x7fff;
+#ifdef RETROPLATFORM
+       rp_cd_change (unitnum, 0);
+       rp_cd_image_change (unitnum, currprefs.cdimagefile[unitnum]);
+#endif
        return 1;
 }
 
 static void close_device (int unitnum)
 {
        struct cdunit *cdu = &cdunits[unitnum];
+       if (cdu->open == false)
+               return;
+       cdda_stop (cdu);
        unload_image (cdu);
        uae_sem_destroy (&cdu->sub_sem);
-}
-
-static int mountme (struct cdunit *cdu, bool checkparse)
-{
-       sys_command_setunit (-1);
-
-       bool sel = false;
-       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, 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);
-                                       cdu->donotmountme = false;
-                                       return -1;
-                               }
-                       }
-               }
-       }
-       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 (cdu);
-               int media = cdu->tracks > 0;
-               write_log (L"CDEMU (%s) selected (media=%d)\n", currprefs.cdimagefile, media);
-               return 1;
-       }
-       return 0;
-}
-
-void cdimage_vsync (void)
-{
-       struct cdunit *cdu = &cdunits[0];
-
-       if (_tcscmp (changed_prefs.cdimagefile, currprefs.cdimagefile)) {
-               _tcscpy (cdu->newfile, changed_prefs.cdimagefile);
-               changed_prefs.cdimagefile[0] = currprefs.cdimagefile[0] = 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 (cdu->imagechange == 0)
-               return;
-       cdu->imagechange--;
-       if (cdu->imagechange > 0)
-               return;
-       _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) {
-               cdu->donotmountme = 1;
-               int un = scsi_do_disk_device_change ();
-               cdu->donotmountme = 0;
-               if (un < 0) {
-                       cdu->donotmountme = -1;
-                       device_func_init (DEVICE_TYPE_ANY); // activate us again
-                       cdu->donotmountme = 0;
-                       parse_image (cdu);
-                       scsi_do_disk_change (255, 1, NULL);
-               }
-       } else {
-               mountme (cdu, true);
-       }
+       cdu->open = false;
+       cdu->enabled = false;
 #ifdef RETROPLATFORM
-       rp_cd_image_change (0, currprefs.cdimagefile);
+       rp_cd_change (unitnum, 1);
+       rp_cd_image_change (unitnum, currprefs.cdimagefile[unitnum]);
 #endif
-       config_changed = 1;
 }
 
 static int ismedia (int unitnum, int quick)
@@ -1216,8 +1215,10 @@ static int ismedia (int unitnum, int quick)
 static struct device_info *info_device (int unitnum, struct device_info *di, int quick)
 {
        struct cdunit *cdu = &cdunits[unitnum];
+       memset (di, 0, sizeof (struct device_info));
        if (!cdu->enabled)
                return 0;
+       di->open = cdu->open;
        di->removable = 1;
        di->bus = unitnum;
        di->target = 0;
@@ -1230,71 +1231,43 @@ static struct device_info *info_device (int unitnum, struct device_info *di, int
        di->sectorspertrack = cdu->cdsize / di->bytespersector;
        if (ismedia (unitnum, 1)) {
                di->media_inserted = 1;
-               _tcscpy (di->mediapath, currprefs.cdimagefile);
+               _tcscpy (di->mediapath, currprefs.cdimagefile[0]);
        }
        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));
+       command_toc (unitnum, &di->toc);
        di->write_protected = 1;
        di->type = INQ_ROMD;
-       di->id = 255;
+       di->unitnum = unitnum + 1;
        _tcscpy (di->label, L"CDEMU");
        return di;
 }
 
-static int check_bus (int flags)
+static void close_bus (void)
 {
-       struct cdunit *cdu = &cdunits[0];
-       cdu->enabled = true;
-       if (!(flags & DEVICE_TYPE_CHECKAVAIL))
-               return 1;
-       if (cdu->donotmountme < 0 || (flags & DEVICE_TYPE_ALLOWEMU))
-               return 1;
-       if (cdu->donotmountme > 0)
-               return 0;
-       if (cdu->imagechange)
-               return 1;
-       int v = currprefs.cdimagefile[0] ? 1 : 0;
-       if (v) {
-               if (mountme (cdu, false) < 0) // is it supported <drive letter:>\?
-                       return 0;
-       }
-       if (currprefs.cdimagefileuse) {
-               v = 1;
+       if (!bus_open) {
+               write_log (L"IMAGE close_bus() when already closed!\n");
+               return;
        }
-       return v;
+       bus_open = 0;
+       write_log (L"IMAGE driver closed.\n");
 }
 
 static int open_bus (int flags)
 {
-       struct cdunit *cdu = &cdunits[0];
-       if (!(flags & DEVICE_TYPE_CHECKAVAIL))
+       if (bus_open) {
+               write_log (L"IOCTL open_bus() more than once!\n");
                return 1;
-       if (cdu->donotmountme < 0 || (flags & DEVICE_TYPE_ALLOWEMU))
-               return 1;
-       if (cdu->donotmountme > 0)
-               return 0;
-
-       mountme (cdu, true);
-#ifdef RETROPLATFORM
-       rp_cd_change (0, 0);
-       rp_cd_image_change (0, currprefs.cdimagefile);
-#endif
+       }
+       bus_open = 1;
+       write_log (L"Image driver open.\n");
        return 1;
 }
 
-static void close_bus (void)
-{
-#ifdef RETROPLATFORM
-       rp_cd_change (0, 1);
-#endif
-}
-
 struct device_functions devicefunc_cdimage = {
-       check_bus, open_bus, close_bus, open_device, close_device, info_device,
+       L"IMAGE",
+       open_bus, close_bus, open_device, close_device, info_device,
        0, 0, 0,
        command_pause, command_stop, command_play, command_volume, command_qcode,
        command_toc, command_read, command_rawread, 0,
-       0, 0, ismedia
+       0, ismedia
 };
index eda5756f9d482c6fa3e272ec2800e2f0daa9dbd6..100153d8026c0125234c22ec20ffc288805e2340 100644 (file)
--- a/cdtv.cpp
+++ b/cdtv.cpp
@@ -83,7 +83,6 @@ 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, cd_volume_stored;
 static int cd_led;
 static int frontpanel;
@@ -133,10 +132,8 @@ static void subreset (void)
 static int get_toc (void)
 {
        datatrack = 0;
-       struct cd_toc_head *t = sys_command_cd_toc (DF_IOCTL, unitnum);
-       if (!t)
+       if (!sys_command_cd_toc (unitnum, &toc))
                return 0;
-       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;
@@ -154,7 +151,7 @@ static void finished_cdplay (void)
 
 static int get_qcode (void)
 {
-       if (!sys_command_cd_qcode (DF_IOCTL, unitnum, cdrom_qcode))
+       if (!sys_command_cd_qcode (unitnum, cdrom_qcode))
                return 0;
        if (cd_playing) {
                if (cdrom_qcode[1] == AUDIO_STATUS_IN_PROGRESS) {
@@ -182,8 +179,8 @@ static void cdaudiostop (void)
        cd_motor = 0;
        if (unitnum < 0)
                return;
-       sys_command_cd_pause (DF_IOCTL, unitnum, 0);
-       sys_command_cd_stop (DF_IOCTL, unitnum);
+       sys_command_cd_pause (unitnum, 0);
+       sys_command_cd_stop (unitnum);
 }
 static void cdaudiostopfp (void)
 {
@@ -194,7 +191,7 @@ static void cdaudiostopfp (void)
 
 static int pause_audio (int pause)
 {
-       sys_command_cd_pause (DF_IOCTL, unitnum, pause);
+       sys_command_cd_pause (unitnum, pause);
        if (!cd_playing) {
                cd_paused = 0;
                cd_audio_status = AUDIO_STATUS_NO_STATUS;
@@ -226,7 +223,7 @@ static int ismedia (void)
 {
        if (unitnum < 0)
                return 0;
-       return sys_command_ismedia (DF_IOCTL, unitnum, 0);
+       return sys_command_ismedia (unitnum, 0);
 }
 
 static int issub (void)
@@ -284,10 +281,10 @@ static void do_play (void)
        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);
+       sys_command_cd_pause (unitnum, 0);
        cd_audio_status = AUDIO_STATUS_PLAY_ERROR;
-       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)) {
+       sys_command_cd_volume (unitnum, (cd_volume_stored << 5) | (cd_volume_stored >> 5), (cd_volume_stored << 5) | (cd_volume_stored >> 5));
+       if (sys_command_cd_play (unitnum, start, end, 0, subfunc)) {
                cd_audio_status = AUDIO_STATUS_IN_PROGRESS;
                cd_playing = 1;
        } else {
@@ -358,8 +355,8 @@ static int play_cd (uae_u8 *p)
                cd_paused = 0;
                cd_motor = 0;
                cd_audio_status = AUDIO_STATUS_PLAY_COMPLETE;
-               sys_command_cd_pause (DF_IOCTL, unitnum, 0);
-               sys_command_cd_stop (DF_IOCTL, unitnum);
+               sys_command_cd_pause (unitnum, 0);
+               sys_command_cd_stop (unitnum);
                cd_isready = 50;
                cd_error = 1;
                return 0;
@@ -553,8 +550,6 @@ static void cdrom_command_thread (uae_u8 b)
                        cdrom_command_output[0] = flag;
                        cdrom_command_accepted (1, s, &cdrom_command_cnt_in);
                        cd_finished = 0;
-                       if (first == -1)
-                               first = 100;
                }
                break;
        case 0x82:
@@ -616,18 +611,16 @@ static void cdrom_command_thread (uae_u8 b)
        }
 }
 
-static uae_u8 *read_raw (int sector, int size)
+static int read_raw (int sector, uae_u8 *dst, int blocksize)
 {
        int osector = sector - 150;
        static struct zfile *f;
        static int track;
        int trackcnt;
        TCHAR fname[MAX_DPATH];
-       static uae_u8 buf[4096];
        uae_u32 prevlsn = 0;
        struct cd_toc *t = &toc.toc[0];
 
-       memset (buf, 0, sizeof buf);
        trackcnt = 0;
        for (;;) {
                int lsn = t->paddress;
@@ -651,18 +644,18 @@ static uae_u8 *read_raw (int sector, int size)
                track = trackcnt;
        }
        if (f) {
-               write_log (L"CDTV fakeraw: %dx%d=%d\n", sector, size, sector * size);
-               zfile_fseek (f, sector * size, SEEK_SET);
-               zfile_fread (buf, size, 1, f);
-               return buf;
+               write_log (L"CDTV fakeraw: %dx%d=%d\n", sector, blocksize, sector * blocksize);
+               zfile_fseek (f, sector * blocksize, SEEK_SET);
+               zfile_fread (dst, blocksize, 1, f);
+               return 1;
        }
-       return sys_command_cd_rawread (DF_IOCTL, unitnum, NULL, osector, size, 1);
+       return sys_command_cd_rawread (unitnum, dst, osector, blocksize, 1);
 }
 
 static void dma_do_thread (void)
 {
        static int readsector;
-       uae_u8 *p = NULL;
+       int didread = 0;
        int cnt;
 
        while (dma_finished)
@@ -677,13 +670,14 @@ static void dma_do_thread (void)
 #endif
        dma_wait += cnt * (uae_u64)312 * 50 / 75 + 1;
        while (cnt > 0 && dmac_dma) {
-               if (!p || readsector != (cdrom_offset / cdtv_sectorsize)) {
+               uae_u8 buffer[2352];
+               if (!didread || readsector != (cdrom_offset / cdtv_sectorsize)) {
                        readsector = cdrom_offset / cdtv_sectorsize;
                        if (cdtv_sectorsize == 2336)
-                               p = read_raw (readsector, cdtv_sectorsize);
+                               didread = read_raw (readsector, buffer, cdtv_sectorsize);
                        else
-                               p = sys_command_cd_read (DF_IOCTL, unitnum, NULL, readsector, 1);
-                       if (!p) {
+                               didread = sys_command_cd_read (unitnum, buffer, readsector, 1);
+                       if (!didread) {
                                cd_error = 1;
                                activate_stch = 1;
                                write_log (L"CDTV: CD read error!\n");
@@ -691,8 +685,8 @@ static void dma_do_thread (void)
                        }
 
                }
-               put_byte (dmac_acr, p[(cdrom_offset % cdtv_sectorsize) + 0]);
-               put_byte (dmac_acr + 1, p[(cdrom_offset % cdtv_sectorsize) + 1]);
+               put_byte (dmac_acr, buffer[(cdrom_offset % cdtv_sectorsize) + 0]);
+               put_byte (dmac_acr + 1, buffer[(cdrom_offset % cdtv_sectorsize) + 1]);
                cnt--;
                dmac_acr += 2;
                cdrom_length -= 2;
@@ -747,10 +741,10 @@ static void *dev_thread (void *p)
                        }
                        break;
                case 0x0102: // pause
-                       sys_command_cd_pause (DF_IOCTL, unitnum, 1);
+                       sys_command_cd_pause (unitnum, 1);
                        break;
                case 0x0103: // unpause
-                       sys_command_cd_pause (DF_IOCTL, unitnum, 0);
+                       sys_command_cd_pause (unitnum, 0);
                        break;
                case 0x0104: // stop
                        cdaudiostop ();
@@ -787,8 +781,8 @@ static void init_play (int start, int end)
        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);
+       write_log (L"PLAY CD AUDIO from %06X (%d) to %06X (%d)\n",
+               lsn2msf (start), start, lsn2msf (end), end);
 #endif
        play_state = 1;
        subreset ();
@@ -950,7 +944,7 @@ static void tp_bput (int addr, uae_u8 v)
                if (cd_volume > 1023)
                        cd_volume = 1023;
                if (unitnum >= 0)
-                       sys_command_cd_volume (DF_IOCTL, unitnum, (cd_volume << 6) | (cd_volume >> 4));
+                       sys_command_cd_volume (unitnum, (cd_volume << 5) | (cd_volume >> 5), (cd_volume << 5) | (cd_volume >> 5));
                cd_volume_stored = cd_volume;
                cd_volume = 0;
                volstrobe2 = 1;
@@ -1059,29 +1053,29 @@ void cdtv_getdmadata (uae_u32 *acr)
 static void do_hunt (void)
 {
        int i;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               if (sys_command_ismedia (DF_IOCTL, i, 1) > 0)
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (sys_command_ismedia (i, 1) > 0)
                        break;
        }
-       if (i == MAX_TOTAL_DEVICES) {
-               if (unitnum >= 0 && sys_command_ismedia (DF_IOCTL, unitnum, 1) >= 0)
+       if (i == MAX_TOTAL_SCSI_DEVICES) {
+               if (unitnum >= 0 && sys_command_ismedia (unitnum, 1) >= 0)
                        return;
-               for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-                       if (sys_command_ismedia (DF_IOCTL, i, 1) >= 0)
+               for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+                       if (sys_command_ismedia (i, 1) >= 0)
                                break;
                }
-               if (i == MAX_TOTAL_DEVICES)
+               if (i == MAX_TOTAL_SCSI_DEVICES)
                        return;
        }
        if (unitnum >= 0) {
                cdaudiostop ();
                int ou = unitnum;
                unitnum = -1;
-               sys_command_close (DF_IOCTL, ou);
+               sys_command_close (ou);
        }
-       if (sys_command_open (DF_IOCTL, i) > 0) {
+       if (sys_command_open (i) > 0) {
                struct device_info di = { 0 };
-               sys_command_info (DF_IOCTL, i, &di, 0);
+               sys_command_info (i, &di, 0);
                unitnum = i;
                cd_hunt = 0;
                write_log (L"CDTV: autodetected unit %d ('%s')\n", unitnum, di.label);
@@ -1285,7 +1279,6 @@ static void cdtv_reset (void)
        cd_finished = 0;
        cd_led = 0;
        stch = 1;
-       first = -1;
 }
 
 static uae_u32 dmac_bget2 (uaecptr addr)
@@ -1568,31 +1561,31 @@ static void open_unit (void)
        struct device_info di1, *di2;
        int first = -1;
        int cdtvunit = -1, audiounit = -1;
-       int opened[MAX_TOTAL_DEVICES];
+       int opened[MAX_TOTAL_SCSI_DEVICES];
        int i;
 
        if (unitnum >= 0)
-               sys_command_close (DF_IOCTL, unitnum);
+               sys_command_close (unitnum);
        unitnum = -1;
        cdtv_reset ();
-       if (!device_func_init (DEVICE_TYPE_IOCTL)) {
+       if (!device_func_init (0)) {
                write_log (L"no CDROM support\n");
                return;
        }
-       for (unitnum = 0; unitnum < MAX_TOTAL_DEVICES; unitnum++) {
+       for (unitnum = 0; unitnum < MAX_TOTAL_SCSI_DEVICES; unitnum++) {
                opened[unitnum] = 0;
-               if (sys_command_open (DF_IOCTL, unitnum)) {
+               if (sys_command_open (unitnum)) {
                        opened[unitnum] = 1;
-                       di2 = sys_command_info (DF_IOCTL, unitnum, &di1, 0);
+                       di2 = sys_command_info (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, NULL, 16, 1);
-                                               if (p) {
-                                                       if (!memcmp (p + 8, "CDTV", 4)) {
+                                               uae_u8 buffer[2048];
+                                               if (sys_command_cd_read (unitnum, buffer, 16, 1)) {
+                                                       if (!memcmp (buffer + 8, "CDTV", 4)) {
                                                                write_log (L"CDTV\n");
                                                                if (cdtvunit < 0)
                                                                        cdtvunit = unitnum;
@@ -1616,9 +1609,9 @@ static void open_unit (void)
                unitnum = first;
        if (unitnum >= 0)
                opened[unitnum] = 0;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                if (opened[i])
-                       sys_command_close (DF_IOCTL, i);
+                       sys_command_close (i);
        }
        cd_media = 0;
        if (unitnum >= 0) {
@@ -1780,7 +1773,7 @@ void cdtv_free (void)
        thread_alive = 0;
        cdaudiostop ();
        if (unitnum >= 0)
-               sys_command_close (DF_IOCTL, unitnum);
+               sys_command_close (unitnum);
        unitnum = -1;
        configured = 0;
 }
index 5267e70f92921c474f146b2e4ffa09f409a844fe..4d6ac5816d8386e334bda995e215877d1a198cef 100644 (file)
@@ -29,6 +29,7 @@
 #include "filesys.h"
 #include "fsdb.h"
 #include "disk.h"
+#include "blkdev.h"
 #include "statusline.h"
 
 static int config_newfilesystem;
@@ -178,6 +179,7 @@ static const TCHAR *dongles[] =
        L"rugby coach", L"cricket captain", L"leviathan",
        NULL
 };
+static const TCHAR *cdmodes[] = { L"", L"image", L"ioctl", L"spti", L"aspi", 0 };
 
 static const TCHAR *obsolete[] = {
        L"accuracy", L"gfx_opengl", L"gfx_32bit_blits", L"32bit_blits",
@@ -554,8 +556,18 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
                }
        }
 
-       if (p->cdimagefile[0] || p->cdimagefileuse)
-               cfgfile_write_str (f, L"cdimage0", p->cdimagefile);
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (p->cdimagefile[i][0] || p->cdimagefileuse[i]) {
+                       TCHAR tmp2[MAX_DPATH];
+                       _stprintf (tmp, L"cdimage%d", i);
+                       _tcscpy (tmp2, p->cdimagefile[i]);
+                       if (p->cdscsidevicetype[i] != 0 || _tcschr (p->cdimagefile[i], ',')) {
+                               _tcscat (tmp2, L",");
+                               _tcscat (tmp2, cdmodes[p->cdscsidevicetype[i]]);
+                       }
+                       cfgfile_write_str (f, tmp, tmp2);
+               }
+       }
 
        if (p->quitstatefile[0])
                cfgfile_write_str (f, L"statefile_quit", p->quitstatefile);
@@ -1127,9 +1139,23 @@ static int cfgfile_parse_host (struct uae_prefs *p, TCHAR *option, TCHAR *value)
                }
        }
 
-       if (cfgfile_path (option, value, L"cdimage0", p->cdimagefile, sizeof p->cdimagefile / sizeof (TCHAR))) {
-               p->cdimagefileuse = true;
-               return 1;
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               TCHAR tmp[20];
+               _stprintf (tmp, L"cdimage%d", i);
+               if (!_tcsicmp (option, tmp)) {
+                       TCHAR *next = _tcsrchr (value, ',');
+                       if (next) {
+                               *next = 0;
+                               TCHAR *next2 = _tcschr (next + 1, ':');
+                               if (next2)
+                                       *next2 = 0;
+                               cfgfile_intval (option, next + 1, tmp, &p->cdscsidevicetype[i], 1);
+                       }
+                       _tcsncpy (p->cdimagefile[i], value, sizeof p->cdimagefile[i]);
+                       p->cdimagefile[i][sizeof p->cdimagefile[i] - 1] = 0;
+                       p->cdimagefileuse[i] = true;
+                       return 1;
+               }
        }
 
        if (cfgfile_intval (option, value, L"sound_frequency", &p->sound_freq, 1)) {
@@ -3607,6 +3633,8 @@ void default_prefs (struct uae_prefs *p, int type)
 
        inputdevice_default_prefs (p);
 
+       blkdev_default_prefs (p);
+
        zfile_fclose (default_file);
        default_file = NULL;
        f = zfile_fopen_empty (NULL, L"configstore", 100000);
index 35f6effbfc9fc3d72548f5674000306e9780eacd..f8211b8806e42bb8c0047eade4ae9513420819bb 100644 (file)
@@ -174,8 +174,7 @@ 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)
-static int hsyncstartpos;
-int hsyncstartposnative;
+int hsyncstartpos;
 static int maxvpos_total = 511;
 int minfirstline = VBLANK_ENDLINE_PAL;
 int equ_vblank_endline = EQU_ENDLINE_PAL;
@@ -2807,7 +2806,6 @@ void init_hz (void)
        } else {
                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 ();
@@ -5083,7 +5081,7 @@ static void vsync_handler (void)
        picasso_handle_vsync ();
 #endif
        audio_vsync ();
-       cdimage_vsync ();
+       blkdev_vsync ();
 
        if (quit_program > 0) {
                /* prevent possible infinite loop at wait_cycles().. */
index 8cdbbca21f857882b8a81ba7ae19db8f2101f7ce..7a17e27400448e0bdb699993f36dede64871c987 100644 (file)
@@ -772,12 +772,13 @@ STATIC_INLINE void fill_line2 (int startpos, int len)
 
 static void fill_line (void)
 {
-       if (hsyncstartposnative > visible_left_border + gfxvidinfo.width || hposendblank) {
+       int hs = coord_hw_to_window_x (hsyncstartpos * 2);
+       if (hs > visible_left_border + gfxvidinfo.width || hposendblank) {
                fill_line2 (visible_left_border, gfxvidinfo.width);
        } else {
-               fill_line2 (visible_left_border, hsyncstartposnative);
+               fill_line2 (visible_left_border, hs);
                hposendblank = 1;
-               fill_line2 (visible_left_border + hsyncstartposnative, gfxvidinfo.width - hsyncstartposnative);
+               fill_line2 (visible_left_border + hs, gfxvidinfo.width - hs);
        }
 }
 
@@ -1918,7 +1919,6 @@ STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_fun
        int i;
        int lastpos = visible_left_border;
        int endpos = visible_left_border + gfxvidinfo.width;
-       int diff = 1 << lores_shift;
 
        for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) {
                int regno = curr_color_changes[i].regno;
index 6c898ab6b490a0b01702e4ab3547b85ab6d662e9..f8765cc98e66b33f269b2e9aae7df1941341280c 100644 (file)
@@ -332,7 +332,6 @@ static void fixcharset (TCHAR *s)
 TCHAR *validatevolumename (TCHAR *s)
 {
        stripsemicolon (s);
-       stripspace (s);
        fixcharset (s);
        striplength (s, 30);
        return s;
index 7d390e7cbc5748a407d0d1721f95f18276b9d8e9..79c83aab13a80422a867301f29fa196e85c7efb3 100644 (file)
@@ -1,7 +1,12 @@
 
-#define MAX_TOTAL_DEVICES 8
 #define DEVICE_SCSI_BUFSIZE (65536 - 1024)
 
+#define SCSI_UNIT_NONE 0
+#define SCSI_UNIT_IMAGE 1
+#define SCSI_UNIT_IOCTL 2
+#define SCSI_UNIT_SPTI 3
+#define SCSI_UNIT_ASPI 4
+
 //#define device_debug write_log
 #define device_debug
 
@@ -45,13 +50,6 @@ struct cd_toc_head
        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)
@@ -63,10 +61,8 @@ struct cd_toc_head
 #define AUDIO_STATUS_PLAY_ERROR     0x14
 #define AUDIO_STATUS_NO_STATUS      0x15
 
-#define DF_SCSI 0
-#define DF_IOCTL 1
-
 struct device_info {
+       bool open;
     int type;
     int media_inserted;
     int removable;
@@ -76,17 +72,15 @@ struct device_info {
     int sectorspertrack;
     int bytespersector;
     int bus, target, lun;
-    int id;
+    int unitnum;
     TCHAR label[MAX_DPATH];
        TCHAR mediapath[MAX_DPATH];
+       TCHAR vendorid[10];
+       TCHAR productid[18];
+       TCHAR revision[6];
        struct cd_toc_head toc;
 };
 
-struct device_scsi_info {
-    uae_u8 *buffer;
-    int bufsize;
-};
-
 struct amigascsi
 {
     uae_u8 *data;
@@ -105,10 +99,9 @@ struct amigascsi
 typedef int (*check_bus_func)(int flags);
 typedef int (*open_bus_func)(int flags);
 typedef void (*close_bus_func)(void);
-typedef int (*open_device_func)(int);
+typedef int (*open_device_func)(int, const TCHAR*);
 typedef void (*close_device_func)(int);
 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*);
@@ -118,68 +111,64 @@ typedef void (*play_subchannel_callback)(uae_u8*, int);
 typedef int (*pause_func)(int, int);
 typedef int (*stop_func)(int);
 typedef int (*play_func)(int, int, int, int, play_subchannel_callback);
-typedef void (*volume_func)(int, uae_u16);
+typedef uae_u32 (*volume_func)(int, uae_u16, uae_u16);
 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 (*toc_func)(int, struct cd_toc_head*);
+typedef int (*read_func)(int, uae_u8*, int, int);
+typedef int (*rawread_func)(int, uae_u8*, int, int, int, uae_u16);
 typedef int (*write_func)(int, uae_u8*, int, int);
 typedef int (*isatapi_func)(int);
 typedef int (*ismedia_func)(int, int);
 
 struct device_functions {
-       check_bus_func checkbus;
-    open_bus_func openbus;
-    close_bus_func closebus;
-    open_device_func opendev;
-    close_device_func closedev;
-    info_device_func info;
-    execscsicmd_out_func exec_out;
-    execscsicmd_in_func exec_in;
-    execscsicmd_direct_func exec_direct;
-
-    pause_func pause;
-    stop_func stop;
-    play_func play;
+       const TCHAR *name;
+       open_bus_func openbus;
+       close_bus_func closebus;
+       open_device_func opendev;
+       close_device_func closedev;
+       info_device_func info;
+       execscsicmd_out_func exec_out;
+       execscsicmd_in_func exec_in;
+       execscsicmd_direct_func exec_direct;
+
+       pause_func pause;
+       stop_func stop;
+       play_func play;
        volume_func volume;
-    qcode_func qcode;
-    toc_func toc;
-    read_func read;
-    rawread_func rawread;
-    write_func write;
+       qcode_func qcode;
+       toc_func toc;
+       read_func read;
+       rawread_func rawread;
+       write_func write;
 
-    isatapi_func isatapi;
-
-    scsiinfo_func scsiinfo;
-
-    ismedia_func ismedia;
+       isatapi_func isatapi;
+       ismedia_func ismedia;
 
 };
 
-extern struct device_functions *device_func[2];
+extern struct device_functions *device_func[MAX_TOTAL_SCSI_DEVICES];
 
 extern int device_func_init(int flags);
 extern void device_func_reset(void);
-extern int sys_command_open (int mode, int unitnum);
-extern void sys_command_close (int mode, int unitnum);
+extern int sys_command_open (int unitnum);
+extern void sys_command_close (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, 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, 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 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 struct device_info *sys_command_info (int unitnum, struct device_info *di, int);
+extern int sys_command_cd_pause (int unitnum, int paused);
+extern void sys_command_cd_stop (int unitnum);
+extern int sys_command_cd_play (int unitnum, int startlsn, int endlsn, int);
+extern int sys_command_cd_play (int unitnum, int startlsn, int endlsn, int scan, play_subchannel_callback subfunc);
+extern uae_u32 sys_command_cd_volume (int unitnum, uae_u16 volume_left, uae_u16 volume_right);
+extern int sys_command_cd_qcode (int unitnum, uae_u8*);
+extern int sys_command_cd_toc (int unitnum, struct cd_toc_head*);
+extern int sys_command_cd_read (int unitnum, uae_u8 *data, int block, int size);
+extern int sys_command_cd_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize);
+extern int sys_command_cd_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize, uae_u8 scsicmd9, uae_u8 subs);
+extern int sys_command_read (int unitnum, uae_u8 *data, int block, int size);
+extern int sys_command_write (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);
+extern int sys_command_ismedia (int unitnum, int quick);
 
 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);
@@ -187,11 +176,17 @@ extern void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, u
 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);
 
-extern void cdimage_vsync (void);
+extern void blkdev_vsync (void);
 
 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
+extern void tolongbcd (uae_u8 *p, int v);
+
+extern void blkdev_default_prefs (struct uae_prefs *p);
+extern void blkdev_fix_prefs (struct uae_prefs *p);
+extern int isaudiotrack (struct cd_toc_head*, int block);
+extern int isdatatrack (struct cd_toc_head*, int block);
+
index 1fe32c9fd0fea772a69d19f7b0a8a27ec612f4dd..61d779416ea200a1a9f00601b01147a432280e95 100644 (file)
@@ -110,7 +110,7 @@ extern uae_u16 INTREQR (void);
 
 extern int maxhpos, maxhpos_short;
 extern int maxvpos, maxvpos_nom;
-extern int hsyncstartposnative;
+extern int hsyncstartpos;
 extern int minfirstline, vblank_endline, numscrlines;
 extern int vblank_hz, fake_vblank_hz, vblank_skip, doublescan;
 extern frame_time_t syncbase;
index fa7f77c3ffcd6f147b520d8decf4cba163eb0318..8e5f38544a5acd9baa06b83e74f522101c629563 100644 (file)
@@ -7,6 +7,29 @@
 #define IOERR_UNITBUSY  -6
 #define IOERR_SELFTEST  -7
 
+#define CDERR_NotSpecified   20   /* general catchall                    */
+#define CDERR_NoSecHdr      21   /* couldn't even find a sector          */
+#define CDERR_BadSecPreamble 22   /* sector looked wrong                 */
+#define CDERR_BadSecID      23   /* ditto                                */
+#define CDERR_BadHdrSum      24   /* header had incorrect checksum       */
+#define CDERR_BadSecSum      25   /* data had incorrect checksum         */
+#define CDERR_TooFewSecs     26   /* couldn't find enough sectors        */
+#define CDERR_BadSecHdr      27   /* another "sector looked wrong"       */
+#define CDERR_WriteProt      28   /* can't write to a protected disk     */
+#define CDERR_NoDisk        29   /* no disk in the drive                 */
+#define CDERR_SeekError      30   /* couldn't find track 0               */
+#define CDERR_NoMem         31   /* ran out of memory                    */
+#define CDERR_BadUnitNum     32   /* asked for a unit > NUMUNITS         */
+#define CDERR_BadDriveType   33   /* not a drive cd.device understands   */
+#define CDERR_DriveInUse     34   /* someone else allocated the drive    */
+#define CDERR_PostReset      35   /* user hit reset; awaiting doom       */
+#define CDERR_BadDataType    36   /* data on disk is wrong type          */
+#define CDERR_InvalidState   37   /* invalid cmd under current conditions */
+
+#define CDERR_Phase         42   /* illegal or unexpected SCSI phase     */
+#define CDERR_NoBoard       50   /* open failed for non-existant board   */
+
+
 #define TDERR_DiskChanged 29
 
 #define CMD_INVALID    0
 #define TAG_SKIP   3
 #define TAG_USER   (1 << 31)
 
-#define     NSDEVTYPE_UNKNOWN       0
-#define     NSDEVTYPE_GAMEPORT      1
-#define     NSDEVTYPE_TIMER         2
-#define     NSDEVTYPE_KEYBOARD      3
-#define     NSDEVTYPE_INPUT         4
-#define     NSDEVTYPE_TRACKDISK     5
-#define     NSDEVTYPE_CONSOLE       6
-#define     NSDEVTYPE_SANA2         7
-#define     NSDEVTYPE_AUDIO         8
-#define     NSDEVTYPE_CLIPBOARD     9
-#define     NSDEVTYPE_PRINTER       10
-#define     NSDEVTYPE_SERIAL        11
-#define     NSDEVTYPE_PARALLEL      12
-
-#define CMD_MOTOR      9
-#define CMD_SEEK       10
-#define CMD_FORMAT     11
-#define CMD_REMOVE     12
-#define CMD_CHANGENUM  13
-#define CMD_CHANGESTATE        14
-#define CMD_PROTSTATUS 15
-#define CMD_GETDRIVETYPE 18
-#define CMD_GETNUMTRACKS 19
-#define CMD_ADDCHANGEINT 20
-#define CMD_REMCHANGEINT 21
-#define CMD_GETGEOMETRY        22
-#define CMD_GETDRIVETYPE 18
-#define CMD_GETNUMTRACKS 19
-#define CMD_ADDCHANGEINT 20
-#define CMD_REMCHANGEINT 21
-#define CMD_GETGEOMETRY        22
-#define HD_SCSICMD 28
+#define NSDEVTYPE_UNKNOWN       0
+#define NSDEVTYPE_GAMEPORT      1
+#define NSDEVTYPE_TIMER         2
+#define NSDEVTYPE_KEYBOARD      3
+#define NSDEVTYPE_INPUT         4
+#define NSDEVTYPE_TRACKDISK     5
+#define NSDEVTYPE_CONSOLE       6
+#define NSDEVTYPE_SANA2         7
+#define NSDEVTYPE_AUDIO         8
+#define NSDEVTYPE_CLIPBOARD     9
+#define NSDEVTYPE_PRINTER       10
+#define NSDEVTYPE_SERIAL        11
+#define NSDEVTYPE_PARALLEL      12
 
-/* Trackdisk64 support */
-#define TD_READ64 24
-#define TD_WRITE64 25
-#define TD_SEEK64 26
-#define TD_FORMAT64 27
+#define CMD_MOTOR                       9
+#define CMD_SEEK                       10
+#define CMD_FORMAT                     11
+#define CMD_REMOVE                     12
+#define CMD_CHANGENUM          13
+#define CMD_CHANGESTATE                14
+#define CMD_PROTSTATUS         15
+#define CMD_GETDRIVETYPE       18
+#define CMD_GETNUMTRACKS       19
+#define CMD_ADDCHANGEINT       20
+#define CMD_REMCHANGEINT       21
+#define CMD_GETGEOMETRY                22
+#define CMD_GETDRIVETYPE       18
+#define CMD_GETNUMTRACKS       19
+#define CMD_ADDCHANGEINT       20
+#define CMD_REMCHANGEINT       21
+#define CMD_GETGEOMETRY                22
+#define CD_EJECT                       23
+#define TD_READ64                      24
+#define TD_WRITE64                     25
+#define TD_SEEK64                      26
+#define TD_FORMAT64                    27
+#define HD_SCSICMD                     28
+#define CD_INFO                                32
+#define CD_CONFIG                      33
+#define CD_TOCMSF                      34
+#define CD_TOCLSN                      35
+#define CD_READXL                      36
+#define CD_PLAYTRACK           37
+#define CD_PLAYMSF                     38
+#define CD_PLAYLSN                     39
+#define CD_PAUSE                       40
+#define CD_SEARCH                      41
+#define CD_QCODEMSF                    42
+#define CD_QCODELSN                    43
+#define CD_ATTENUATE           44
+#define CD_ADDFRAMEINT         45
+#define CD_REMFRAMEINT         46
 
 /* New Style Devices (NSD) support */
 #define NSCMD_TD_READ64 0xc000
index 7c106f0e572cbe8fc666b8fb3c380ddbed5a4f71..80479399ce890e61e79f02f2dca8f40955baa7ab 100644 (file)
@@ -21,6 +21,8 @@ struct strlist {
        int unknown;
 };
 
+#define MAX_TOTAL_SCSI_DEVICES 8
+
 /* maximum number native input devices supported (single type) */
 #define MAX_INPUT_DEVICES 8
 /* maximum number of native input device's buttons and axles supported */
@@ -282,8 +284,9 @@ struct uae_prefs {
        TCHAR sername[256];
        TCHAR amaxromfile[MAX_DPATH];
        TCHAR a2065name[MAX_DPATH];
-       TCHAR cdimagefile[MAX_DPATH];
-       bool cdimagefileuse;
+       TCHAR cdimagefile[MAX_TOTAL_SCSI_DEVICES][MAX_DPATH];
+       bool cdimagefileuse[MAX_TOTAL_SCSI_DEVICES];
+       int cdscsidevicetype[MAX_TOTAL_SCSI_DEVICES];
        TCHAR quitstatefile[MAX_DPATH];
 
        TCHAR path_floppy[256];
index f35bbf5d6699a61fb5f2043b115fb19f8cbe8786..ddd14cb2aed743da14b1eb6a2fa6622c8aaae38e 100644 (file)
@@ -12,7 +12,7 @@ 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 *pollmode);
+int scsi_do_disk_change (int unitnum, int insert, int *pollmode);
 int scsi_do_disk_device_change (void);
 
 extern int log_scsi;
index 2d021c3b2e9324a071e632ec5d8918db250dd710..1917238ebb1ccaa6e0e7384c3deb0f82a86d3ac3 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -390,6 +390,7 @@ void fixup_prefs (struct uae_prefs *p)
                p->maprom = 0x0f000000;
        if (p->tod_hack && p->cs_ciaatod == 0)
                p->cs_ciaatod = p->ntscmode ? 2 : 1;
+       blkdev_fix_prefs (p);
        target_fixup_options (p);
 }
 
index e4899ba0befe0d0b70f5872ffee41dc75d1f4cf6..7d267ce7406d841995838502296b4e9d22638264 100644 (file)
@@ -44,7 +44,7 @@ struct scsi_info {
        int isatapi;
        int removable;
 };
-static struct scsi_info si[MAX_TOTAL_DEVICES];
+static struct scsi_info si[MAX_TOTAL_SCSI_DEVICES];
 static int unitcnt;
 
 static int getversion(const TCHAR *name, VS_FIXEDFILEINFO *ver)
@@ -710,7 +710,7 @@ static void scan_scsi_bus (SCSI *scgp, int flags)
 
                                        write_log (L"ASPI: %d:%d:%d '%s' '%s' '%s' ",
                                                scgp->addr.scsibus,scgp->addr.target,scgp->addr.lun, vend, prod, rev);
-                                       if (unitcnt < MAX_TOTAL_DEVICES) {
+                                       if (unitcnt < MAX_TOTAL_SCSI_DEVICES) {
                                                struct scsi_info *cis = &si[unitcnt];
                                                int use = 0;
                                                write_log (L"[");
@@ -820,15 +820,6 @@ static uae_u8 *execscsicmd_in (int unitnum, uae_u8 *data, int len, int *outlen)
 
 static SCSI *scsi_handle;
 
-static int check_scsi_bus (int flags)
-{
-       if (open_driver (NULL)) {
-               close_driver ();
-               return 1;
-       }
-       return 0;
-}
-
 static int open_scsi_bus (int flags)
 {
        SCSI *scgp = openscsi (-1, -1, -1);
@@ -885,7 +876,7 @@ static int mediacheck_full (int unitnum, struct device_info *di)
        return 1;
 }
 
-static int open_scsi_device (int unitnum)
+static int open_scsi_device (int unitnum, const TCHAR *ident)
 {
        if (unitnum >= unitcnt)
                return 0;
@@ -982,13 +973,14 @@ static struct device_info *info_device (int unitnum, struct device_info *di, int
        struct scsi_info *sif = &si[unitnum];
        if (unitnum >= unitcnt)
                return 0;
+       di->open = sif->handle != 0;
        di->bus = sif->scsibus;
        di->target = sif->target;
        di->lun = sif->lun;
        di->media_inserted = mediacheck (unitnum);
        di->type = sif->type;
        mediacheck_full (unitnum, di);
-       di->id = unitnum + 1;
+       di->unitnum = unitnum + 1;
        di->removable = sif->removable;
        _tcscpy (di->label, sif->label);
        if (log_scsi) {
@@ -1019,15 +1011,9 @@ static int check_isatapi (int unitnum)
        return si[unitnum].isatapi;
 }
 
-static struct device_scsi_info *scsi_info (int unitnum, struct device_scsi_info *dsi)
-{
-       dsi->buffer = si[unitnum].buf;
-       dsi->bufsize = DEVICE_SCSI_BUFSIZE;
-       return dsi;
-}
-
 struct device_functions devicefunc_win32_aspi = {
-       check_scsi_bus, open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device,
+       L"ASPI",
+       open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device,
        execscsicmd_out, execscsicmd_in, execscsicmd_direct,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, check_isatapi, scsi_info, 0
+       0, 0, 0, 0, 0, 0, 0, 0, 0, check_isatapi, 0
 };
index 52c5364a0f99ce2b2409ea5af13ed154bb306de4..177da530448f51c08924f29fa04e009e49213372 100644 (file)
@@ -42,17 +42,16 @@ struct dev_info_ioctl {
        TCHAR drvletter;
        TCHAR drvlettername[10];
        TCHAR devname[30];
-       int mediainserted;
        int type;
-       int blocksize;
-       CDROM_TOC toc;
+       CDROM_TOC cdromtoc;
        UINT errormode;
        int playend;
        int fullaccess;
        int cdda_play_finished;
        int cdda_play;
        int cdda_paused;
-       int cdda_volume;
+       int cdda_volume[2];
+       int cdda_scan;
        int cdda_volume_main;
        uae_u32 cd_last_pos;
        HWAVEOUT cdda_wavehandle;
@@ -63,43 +62,57 @@ struct dev_info_ioctl {
        play_subchannel_callback cdda_subfunc;
        struct device_info di;
        uae_sem_t sub_sem, sub_sem2;
+       bool open;
 };
 
-static int MCICDA;
+static struct dev_info_ioctl ciw32[MAX_TOTAL_SCSI_DEVICES];
+static int unittable[MAX_TOTAL_SCSI_DEVICES];
+static int bus_open;
 
-static struct dev_info_ioctl ciw32[MAX_TOTAL_DEVICES];
-
-static void seterrormode (int unitnum)
+static void seterrormode (struct dev_info_ioctl *ciw)
 {
-       ciw32[unitnum].errormode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+       ciw->errormode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
 }
-static void reseterrormode (int unitnum)
+static void reseterrormode (struct dev_info_ioctl *ciw)
 {
-       SetErrorMode (ciw32[unitnum].errormode);
+       SetErrorMode (ciw->errormode);
 }
 
-static void close_device (int unitnum);
-static int open_device (int unitnum);
+static int sys_cddev_open (struct dev_info_ioctl *ciw, int unitnum);
+static void sys_cddev_close (struct dev_info_ioctl *ciw, int unitnum);
 
-static int unitcheck (int unitnum)
+static int getunitnum (struct dev_info_ioctl *ciw)
 {
-       if (unitnum >= MAX_TOTAL_DEVICES) {
-               if (unitnum < 'A' || unitnum > 'Z')
-                       return 0;
-               return 1;
+       if (!ciw)
+               return -1;
+       int idx = ciw - &ciw32[0];
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (unittable[i] - 1 == idx)
+                       return i;
        }
+       return -1;
+}
+
+static struct dev_info_ioctl *unitcheck (int unitnum)
+{
+       if (unitnum < 0 || unitnum >= MAX_TOTAL_SCSI_DEVICES)
+               return NULL;
+       if (unittable[unitnum] <= 0)
+               return NULL;
+       unitnum = unittable[unitnum] - 1;
        if (ciw32[unitnum].drvletter == 0)
-               return 0;
-       return 1;
+               return NULL;
+       return &ciw32[unitnum];
 }
 
-static bool unitisopen (int unitnum)
+static struct dev_info_ioctl *unitisopen (int unitnum)
 {
-       if (!unitcheck (unitnum))
-               return false;
-       if (ciw32[unitnum].tempbuffer == NULL)
-               return false;
-       return true;
+       struct dev_info_ioctl *di = unitcheck (unitnum);
+       if (!di)
+               return NULL;
+       if (di->open == false)
+               return NULL;
+       return di;
 }
 
 static int mcierr (TCHAR *str, DWORD err)
@@ -112,7 +125,7 @@ static int mcierr (TCHAR *str, DWORD err)
        return err;
 }
 
-static int win32_error (int unitnum, const TCHAR *format,...)
+static int win32_error (struct dev_info_ioctl *ciw, int unitnum, const TCHAR *format,...)
 {
        LPVOID lpMsgBuf;
        va_list arglist;
@@ -121,8 +134,8 @@ static int win32_error (int unitnum, const TCHAR *format,...)
 
        if (err == ERROR_WRONG_DISK) {
                write_log (L"IOCTL: media change, re-opening device\n");
-               close_device (unitnum);
-               if (!open_device (unitnum))
+               sys_cddev_close (ciw, unitnum);
+               if (!sys_cddev_open (ciw, unitnum))
                        write_log (L"IOCTL: re-opening failed!\n");
                return -1;
        }
@@ -132,15 +145,13 @@ static int win32_error (int unitnum, const TCHAR *format,...)
                NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR)&lpMsgBuf, 0, NULL);
        if (log_scsi)
-               write_log (L"IOCTL: unit=%d %s,%d: %s\n", unitnum, buf, err, (TCHAR*)lpMsgBuf);
+               write_log (L"IOCTL: unit=%d,%s,%d: %s\n", unitnum, buf, err, (TCHAR*)lpMsgBuf);
        va_end (arglist);
        return err;
 }
 
-static int close_createfile (int unitnum)
+static int close_createfile (struct dev_info_ioctl *ciw)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
        ciw->fullaccess = 0;
        if (ciw->h != INVALID_HANDLE_VALUE) {
                if (log_scsi)
@@ -154,15 +165,14 @@ static int close_createfile (int unitnum)
        return 0;
 }
 
-static int open_createfile (int unitnum, int fullaccess)
+static int open_createfile (struct dev_info_ioctl *ciw, int fullaccess)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
        int cnt = 50;
        DWORD len;
 
        if (ciw->h != INVALID_HANDLE_VALUE) {
                if (fullaccess && ciw->fullaccess == 0) {
-                       close_createfile (unitnum);
+                       close_createfile (ciw);
                } else {
                        return 1;
                }
@@ -231,7 +241,6 @@ static void *cdda_play (void *v)
 {
        DWORD len;
        struct dev_info_ioctl *ciw = (struct dev_info_ioctl*)v;
-       int unitnum = ciw32 - ciw;
        int cdda_pos;
        int num_sectors = CDDA_BUFFERS;
        int bufnum;
@@ -241,7 +250,7 @@ static void *cdda_play (void *v)
        int i;
        WAVEHDR whdr[2];
        MMRESULT mmr;
-       int volume, volume_main;
+       int volume[2], volume_main;
        int oldplay;
        int firstloops;
 
@@ -260,7 +269,7 @@ static void *cdda_play (void *v)
        bufon[0] = bufon[1] = 0;
        bufnum = 0;
        buffered = 0;
-       volume = -1;
+       volume[0] = volume[1] = -1;
        volume_main = -1;
 
        if (cdda_openwav (ciw)) {
@@ -292,12 +301,17 @@ static void *cdda_play (void *v)
                                firstloops = 25;
                                write_log (L"CDDA: playing from %d to %d\n", ciw->cdda_start, ciw->cdda_end);
                                ciw->subcodevalid = false;
+                               while (ciw->cdda_paused && ciw->cdda_play > 0)
+                                       Sleep (10);
                        }
 
                        if ((cdda_pos < ciw->cdda_end || ciw->cdda_end == 0xffffffff) && !ciw->cdda_paused && ciw->cdda_play) {
                                RAW_READ_INFO rri;
                                int sectors = num_sectors;
 
+                               if (!isaudiotrack (&ciw->di.toc, cdda_pos))
+                                       goto end; // data track?
+
                                uae_sem_wait (&ciw->sub_sem);
                                ciw->subcodevalid = false;
                                memset (ciw->subcode, 0, sizeof ciw->subcode);
@@ -312,7 +326,7 @@ static void *cdda_play (void *v)
                                } else {
 
                                        firstloops = -1;
-                                       seterrormode (unitnum);
+                                       seterrormode (ciw);
                                        rri.DiskOffset.QuadPart = 2048 * (cdda_pos + 0);
                                        rri.SectorCount = sectors;
                                        rri.TrackMode = RawWithSubCode;
@@ -332,7 +346,7 @@ static void *cdda_play (void *v)
                                                }
                                                ciw->subcodevalid = true;
                                        }
-                                       reseterrormode (unitnum);
+                                       reseterrormode (ciw);
                                }
 
                                uae_sem_post (&ciw->sub_sem);
@@ -342,18 +356,20 @@ static void *cdda_play (void *v)
                                        uae_sem_post (&ciw->sub_sem2);
                                }
 
-
-                               volume = ciw->cdda_volume;
                                volume_main = currprefs.sound_volume;
-                               int vol_mult = (100 - volume_main) * volume / 100;
-                               if (vol_mult)
-                                       vol_mult++;
-                               if (vol_mult >= 65536)
-                                       vol_mult = 65536;
+                               int vol_mult[2];
+                               for (int j = 0; j < 2; j++) {
+                                       volume[j] = ciw->cdda_volume[j];
+                                       vol_mult[j] = (100 - volume_main) * volume[j] / 100;
+                                       if (vol_mult[j])
+                                               vol_mult[j]++;
+                                       if (vol_mult[j] >= 32768)
+                                               vol_mult[j] = 32768;
+                               }
                                uae_s16 *p = (uae_s16*)(px[bufnum]);
                                for (i = 0; i < num_sectors * 2352 / 4; i++) {
-                                       p[i * 2 + 0] = p[i * 2 + 0] * vol_mult / 65536;
-                                       p[i * 2 + 1] = p[i * 2 + 1] * vol_mult / 65536;
+                                       p[i * 2 + 0] = p[i * 2 + 0] * vol_mult[0] / 32768;
+                                       p[i * 2 + 1] = p[i * 2 + 1] * vol_mult[1] / 32768;
                                }
                
                                bufon[bufnum] = 1;
@@ -364,7 +380,13 @@ static void *cdda_play (void *v)
                                }
 
                                if (firstloops < 0) {
-                                       cdda_pos += num_sectors;
+                                       if (ciw->cdda_scan) {
+                                               cdda_pos += ciw->cdda_scan * num_sectors;
+                                               if (cdda_pos < 0)
+                                                       cdda_pos = 0;
+                                       } else  {
+                                               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;
@@ -403,10 +425,8 @@ end:
        return NULL;
 }
 
-static void cdda_stop (int unitnum)
+static void cdda_stop (struct dev_info_ioctl *ciw)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
        if (ciw->cdda_play > 0) {
                ciw->cdda_play = -1;
                while (ciw->cdda_play) {
@@ -421,48 +441,52 @@ static void cdda_stop (int unitnum)
 /* pause/unpause CD audio */
 static int ioctl_command_pause (int unitnum, int paused)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
-       if (!unitisopen (unitnum))
-               return 0;
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
+               return -1;
+       int old = ciw->cdda_paused;
        ciw->cdda_paused = paused;
-       return 1;
+       return old;
 }
 
 
 /* stop CD audio */
 static int ioctl_command_stop (int unitnum)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
-       if (!unitisopen (unitnum))
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
                return 0;
 
-       cdda_stop (unitnum);
+       cdda_stop (ciw);
                
        return 1;
 }
 
-static void ioctl_command_volume (int unitnum, uae_u16 volume)
+static uae_u32 ioctl_command_volume (int unitnum, uae_u16 volume_left, uae_u16 volume_right)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
-       ciw->cdda_volume = volume;
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
+               return -1;
+       uae_u32 old = (ciw->cdda_volume[1] << 16) | (ciw->cdda_volume[0] << 0);
+       ciw->cdda_volume[0] = volume_left;
+       ciw->cdda_volume[1] = volume_right;
+       return old;
 }
 
 /* play CD audio */
 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))
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
                return 0;
 
-       if (!open_createfile (unitnum, 0))
+       if (!open_createfile (ciw, 0))
+               return 0;
+       if (!isaudiotrack (&ciw->di.toc, startlsn))
                return 0;
-       ciw->cdda_paused = 0;
        ciw->cdda_play_finished = 0;
        ciw->cdda_subfunc = subfunc;
+       ciw->cdda_scan = scan > 0 ? 10 : (scan < 0 ? 10 : 0);
        if (!ciw->cdda_play) {
                uae_start_thread (L"cdda_play", cdda_play, ciw, NULL);
        }
@@ -491,22 +515,19 @@ static void sub_deinterleave (uae_u8 *s, uae_u8 *d)
 /* read qcode */
 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);
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
                return 0;
-       }
 
        uae_u8 *p;
        int trk;
-       CDROM_TOC *toc = &ciw->toc;
+       CDROM_TOC *toc = &ciw->cdromtoc;
        int pos;
        int msf;
        int start, end;
        int status;
        bool valid = false;
-       bool regenerate = false;
+       bool regenerate = true;
 
        memset (buf, 0, SUBQ_SIZE);
        p = buf;
@@ -542,7 +563,7 @@ static int ioctl_command_qcode (int unitnum, uae_u8 *buf, int sector)
                if (!valid && sector >= 0) {
                        DWORD len;
                        uae_sem_wait (&ciw->sub_sem);
-                       seterrormode (unitnum);
+                       seterrormode (ciw);
                        RAW_READ_INFO rri;
                        rri.DiskOffset.QuadPart = 2048 * (pos + 0);
                        rri.SectorCount = 1;
@@ -552,7 +573,7 @@ static int ioctl_command_qcode (int unitnum, uae_u8 *buf, int sector)
                                DWORD err = GetLastError ();
                                write_log (L"IOCTL_CDROM_RAW_READ SUBQ CDDA sector %d returned %d\n", pos, err);
                        }
-                       reseterrormode (unitnum);
+                       reseterrormode (ciw);
                        uae_u8 subbuf[SUB_CHANNEL_SIZE];
                        sub_deinterleave (ciw->tempbuffer + 2352, subbuf);
                        uae_sem_post (&ciw->sub_sem);
@@ -593,35 +614,17 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
        UCHAR SenseBuf[32];
 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
 
-static uae_u8 *spti_read (int unitnum, int sector, int sectorsize)
+static int do_raw_scsi (struct dev_info_ioctl *ciw, int unitnum, uae_u8 *cmd, int cmdlen, uae_u8 *data, int datalen)
 {
        DWORD status, returned;
        SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
-       uae_u8 *p = ciw32[unitnum].tempbuffer;
-       /* number of bytes returned depends on type of track:
-       * CDDA = 2352
-       * Mode1 = 2048
-       * Mode2 = 2336
-       * Mode2 Form 1 = 2048
-       * Mode2 Form 2 = 2328
-       */
-       uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 };
-       int len = sizeof cmd;
-
-       if (!unitisopen (unitnum))
+       uae_u8 *p = ciw->tempbuffer;
+       if (!open_createfile (ciw, 1))
                return 0;
-
-       if (!open_createfile (unitnum, 1))
-               return 0;
-       ciw32[unitnum].cd_last_pos = sector;
-       cmd[3] = (uae_u8)(sector >> 16);
-       cmd[4] = (uae_u8)(sector >> 8);
-       cmd[5] = (uae_u8)(sector >> 0);
-       gui_flicker_led (LED_CD, unitnum, 1);
        memset (&swb, 0, sizeof (swb));
-       memcpy (swb.spt.Cdb, cmd, len);
+       memcpy (swb.spt.Cdb, cmd, cmdlen);
        swb.spt.Length = sizeof (SCSI_PASS_THROUGH);
-       swb.spt.CdbLength = len;
+       swb.spt.CdbLength = cmdlen;
        swb.spt.DataIn = SCSI_IOCTL_DATA_IN;
        swb.spt.DataTransferLength = IOCTL_DATA_BUFFER;
        swb.spt.DataBuffer = p;
@@ -629,131 +632,237 @@ static uae_u8 *spti_read (int unitnum, int sector, int sectorsize)
        swb.spt.TimeOutValue = 80 * 60;
        swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
        swb.spt.SenseInfoLength = 32;
-
-       seterrormode (unitnum);
-       status = DeviceIoControl (ciw32[unitnum].h, IOCTL_SCSI_PASS_THROUGH_DIRECT,
+       seterrormode (ciw);
+       status = DeviceIoControl (ciw->h, IOCTL_SCSI_PASS_THROUGH_DIRECT,
                &swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
                &swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
                &returned, NULL);
-       reseterrormode (unitnum);
+       reseterrormode (ciw);
        if (!status) {
                DWORD err = GetLastError ();
-               write_log (L"IOCTL_RAW_SCSI unit %d, ERR=%d ", unitnum, err);
+               write_log (L"IOCTL_RAW_SCSI unit %d, CMD=%d, ERR=%d ", unitnum, cmd[0], err);
                return 0;
        }
-       return p;
+       memcpy (data, p, swb.spt.DataTransferLength > datalen ? datalen : swb.spt.DataTransferLength);
+       return 1;
+}
+
+static int spti_inquiry (struct dev_info_ioctl *ciw, int unitnum, uae_u8 *data)
+{
+       uae_u8 cmd[6] = { 0x12,0,0,0,36,0 }; /* INQUIRY */
+       int len = sizeof cmd;
+
+       do_raw_scsi (ciw, unitnum, cmd, len, data, 256);
+       return 1;
+}
+
+static int spti_read (struct dev_info_ioctl *ciw, int unitnum, uae_u8 *data, int sector, int sectorsize)
+{
+       /* number of bytes returned depends on type of track:
+       * CDDA = 2352
+       * Mode1 = 2048
+       * Mode2 = 2336
+       * Mode2 Form 1 = 2048
+       * Mode2 Form 2 = 2328
+       */
+       uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 };
+       ciw->cd_last_pos = sector;
+       cmd[3] = (uae_u8)(sector >> 16);
+       cmd[4] = (uae_u8)(sector >> 8);
+       cmd[5] = (uae_u8)(sector >> 0);
+       gui_flicker_led (LED_CD, unitnum, 1);
+       int len = sizeof cmd;
+       return do_raw_scsi (ciw, unitnum,  cmd, len, data, sectorsize);
 }
 
-uae_u8 *ioctl_command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize)
+static void sub_to_deinterleaved (const 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++;
+       }
+}
+
+static int ioctl_command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize, uae_u16 extra)
+{
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
+               return 0;
+
        RAW_READ_INFO rri;
        DWORD len;
-       uae_u8 *p = ciw32[unitnum].tempbuffer;
+       uae_u8 *p = ciw->tempbuffer;
+       int ret = 0;
 
        if (log_scsi)
                write_log (L"IOCTL rawread unit=%d sector=%d blocksize=%d\n", unitnum, sector, sectorsize);
        if (!os_vista)
-               return spti_read (unitnum, sector, sectorsize);
-       if (!open_createfile (unitnum, 1))
+               return spti_read (ciw, unitnum, data, sector, sectorsize);
+       if (!open_createfile (ciw, 1))
                return 0;
-       cdda_stop (unitnum);
-       if (sectorsize != 2336 && sectorsize != 2352 && sectorsize != 2048)
-               return 0;
-       while (size-- > 0) {
-               gui_flicker_led (LED_CD, unitnum, 1);
-               seterrormode (unitnum);
+       cdda_stop (ciw);
+       gui_flicker_led (LED_CD, unitnum, 1);
+       if (sectorsize > 0) {
+               if (sectorsize != 2336 && sectorsize != 2352 && sectorsize != 2048)
+                       return 0;
+               seterrormode (ciw);
                rri.DiskOffset.QuadPart = sector * 2048;
                rri.SectorCount = 1;
                rri.TrackMode = RawWithSubCode;
                len = sectorsize;
                memset (p, 0, sectorsize);
-               if (!DeviceIoControl (ciw32[unitnum].h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri,
+               if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri,
                        p, IOCTL_DATA_BUFFER, &len, NULL)) {
                                DWORD err = GetLastError ();
                                write_log (L"IOCTL rawread unit=%d sector=%d blocksize=%d, ERR=%d\n", unitnum, sector, sectorsize, err);
                }
-               reseterrormode (unitnum);
+               reseterrormode (ciw);
                if (data) {
-                       memcpy (data, p, sectorsize);
+                       if (sectorsize == 2352)
+                               memcpy (data, p, sectorsize);
+                       else
+                               memcpy (data, p + 16, sectorsize);
                        data += sectorsize;
+                       ret += sectorsize;
                }
-               ciw32[unitnum].cd_last_pos = sector;
-               break;
+               ciw->cd_last_pos = sector;
+       } else {
+               uae_u8 cmd9 = extra >> 8;
+               int sync = (cmd9 >> 7) & 1;
+               int headercodes = (cmd9 >> 5) & 3;
+               int userdata = (cmd9 >> 4) & 1;
+               int edcecc = (cmd9 >> 3) & 1;
+               int errorfield = (cmd9 >> 1) & 3;
+               uae_u8 subs = extra & 7;
+               if (subs != 0 && subs != 1 && subs != 2 && subs != 4)
+                       return -1;
+               if (errorfield >= 3)
+                       return -1;
+               uae_u8 *d = data;
+
+               if (isaudiotrack (&ciw->di.toc, sector)) {
+
+                       for (int i = 0; i < size; i++) {
+                               uae_u8 *odata = data;
+                               int blocksize = errorfield == 0 ? 2352 : (errorfield == 1 ? 2352 + 294 : 2352 + 296);
+                               int readblocksize = errorfield == 0 ? 2352 : 2352 + 296;
+                               seterrormode (ciw);
+                               rri.DiskOffset.QuadPart = sector * 2048;
+                               rri.SectorCount = 1;
+                               rri.TrackMode = errorfield > 0 ? RawWithC2AndSubCode : RawWithSubCode;
+                               len = sectorsize;
+                               memset (p, 0, blocksize);
+                               if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri, p, IOCTL_DATA_BUFFER, &len, NULL)) {
+                                       DWORD err = GetLastError ();
+                                       write_log (L"IOCTL rawread unit=%d sector=%d blocksize=%d, ERR=%d\n", unitnum, sector, sectorsize, err);
+                                       if (err) {
+                                               reseterrormode (ciw);
+                                               return ret;
+                                       }
+                               }
+                               reseterrormode (ciw);
+                               if (subs == 0) {
+                                       memcpy (data, p, blocksize);
+                                       data += blocksize;
+                               } else if (subs == 4) { // all, de-interleaved
+                                       memcpy (data, p, blocksize);
+                                       data += blocksize;
+                                       sub_to_deinterleaved (p + readblocksize, data);
+                                       data += SUB_CHANNEL_SIZE;
+                               } else if (subs == 2) { // q-only
+                                       memcpy (data, p, blocksize);
+                                       data += blocksize;
+                                       uae_u8 subdata[SUB_CHANNEL_SIZE];
+                                       sub_to_deinterleaved (p + readblocksize, subdata);
+                                       memcpy (data, subdata + SUB_ENTRY_SIZE, SUB_ENTRY_SIZE);
+                                       p += SUB_ENTRY_SIZE;
+                               } else if (subs == 1) { // all, interleaved
+                                       memcpy (data, p, blocksize);
+                                       memcpy (data + blocksize, p + readblocksize, SUB_CHANNEL_SIZE);
+                                       data += blocksize + SUB_CHANNEL_SIZE;
+                               }
+                               ret += data - odata;
+                               sector++;
+                       }
+               }
+
+
        }
-       if (sectorsize == 2352)
-               return p;
-       return p + 16;
+       return ret;
 }
 
-static int ioctl_command_readwrite (int unitnum, int sector, int size, int write, int blocksize, uae_u8 *data, uae_u8 **ptr)
+static int ioctl_command_readwrite (int unitnum, int sector, int size, int write, uae_u8 *data)
 {
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
+               return 0;
+
        DWORD dtotal;
        int cnt = 3;
-       uae_u8 *p = ciw32[unitnum].tempbuffer;
+       uae_u8 *p = ciw->tempbuffer;
+       int blocksize = ciw->di.bytespersector;
 
-       *ptr = NULL;
-
-       if (!unitisopen (unitnum))
+       if (!open_createfile (ciw, 0))
                return 0;
-
-       if (!open_createfile (unitnum, 0))
-               return 0;
-       cdda_stop (unitnum);
-       ciw32[unitnum].cd_last_pos = sector;
+       cdda_stop (ciw);
+       ciw->cd_last_pos = sector;
        while (cnt-- > 0) {
                gui_flicker_led (LED_CD, unitnum, 1);
-               seterrormode (unitnum);
-               if (SetFilePointer (ciw32[unitnum].h, sector * ciw32[unitnum].blocksize, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
-                       reseterrormode (unitnum);
-                       if (win32_error (unitnum, L"SetFilePointer") < 0)
+               seterrormode (ciw);
+               if (SetFilePointer (ciw->h, sector * ciw->di.bytespersector, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
+                       reseterrormode (ciw);
+                       if (win32_error (ciw, unitnum, L"SetFilePointer") < 0)
                                continue;
                        return 0;
                }
-               reseterrormode (unitnum);
+               reseterrormode (ciw);
                break;
        }
        while (size-- > 0) {
                gui_flicker_led (LED_CD, unitnum, 1);
-               seterrormode (unitnum);
+               seterrormode (ciw);
                if (write) {
                        if (data) {
                                memcpy (p, data, blocksize);
                                data += blocksize;
                        }
-                       if (!WriteFile (ciw32[unitnum].h, p, blocksize, &dtotal, 0)) {
+                       if (!WriteFile (ciw->h, p, blocksize, &dtotal, 0)) {
                                int err;
-                               reseterrormode (unitnum);
-                               err = win32_error (unitnum, L"WriteFile");
+                               reseterrormode (ciw);
+                               err = win32_error (ciw, unitnum, L"WriteFile");
                                if (err < 0)
                                        continue;
                                if (err == ERROR_WRITE_PROTECT)
                                        return -1;
                                return 0;
                        }
-                       *ptr = p;
                } else {
                        dtotal = 0;
-                       if (!ReadFile (ciw32[unitnum].h, p, blocksize, &dtotal, 0)) {
-                               reseterrormode (unitnum);
-                               if (win32_error (unitnum, L"ReadFile") < 0)
+                       if (!ReadFile (ciw->h, p, blocksize, &dtotal, 0)) {
+                               reseterrormode (ciw);
+                               if (win32_error (ciw, unitnum, L"ReadFile") < 0)
                                        continue;
                                return 0;
                        }
                        if (dtotal == 0) {
                                /* ESS Mega (CDTV) "fake" data area returns zero bytes and no error.. */
-                               *ptr = spti_read (unitnum, sector, 2048);
+                               spti_read (ciw, unitnum, data, sector, 2048);
                                if (log_scsi)
-                                       write_log (L"IOCTL unit %d, sector %d: ReadFile()==0. SPTI=%d\n", unitnum, sector, *ptr == 0 ? GetLastError () : 0);
+                                       write_log (L"IOCTL unit %d, sector %d: ReadFile()==0. SPTI=%d\n", unitnum, sector, GetLastError ());
                                return 1;
-                       } else {
-                               *ptr = p;
                        }
                        if (data) {
                                memcpy (data, p, blocksize);
                                data += blocksize;
                        }
                }
-               reseterrormode (unitnum);
+               reseterrormode (ciw);
                gui_flicker_led (LED_CD, unitnum, 1);
        }
        return 1;
@@ -761,39 +870,36 @@ static int ioctl_command_readwrite (int unitnum, int sector, int size, int write
 
 static int ioctl_command_write (int unitnum, uae_u8 *data, int sector, int size)
 {
-       uae_u8 *ptr;
-       return ioctl_command_readwrite (unitnum, sector, size, 1, ciw32[unitnum].blocksize, data, &ptr);
+       return ioctl_command_readwrite (unitnum, sector, size, 1, data);
 }
 
-static uae_u8 *ioctl_command_read (int unitnum, uae_u8 *data, int sector, int size)
+static int ioctl_command_read (int unitnum, uae_u8 *data, int sector, int size)
 {
-       uae_u8 *ptr;
-       if (ioctl_command_readwrite (unitnum, sector, size, 0, ciw32[unitnum].blocksize, data, &ptr) > 0)
-               return ptr;
-       return NULL;
+       return ioctl_command_readwrite (unitnum, sector, size, 0, data);
 }
 
-static int fetch_geometry (int unitnum, struct device_info *di)
+static int fetch_geometry (struct dev_info_ioctl *ciw, int unitnum, struct device_info *di)
 {
        DISK_GEOMETRY geom;
        DWORD len;
        int cnt = 3;
 
-       if (!open_createfile (unitnum, 0))
+       if (!open_createfile (ciw, 0))
                return 0;
-       uae_sem_wait (&ciw32[unitnum].sub_sem);
-       seterrormode (unitnum);
+       uae_sem_wait (&ciw->sub_sem);
+       seterrormode (ciw);
        while (cnt-- > 0) {
-               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)
+               if (!DeviceIoControl (ciw->h, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof (geom), &len, NULL)) {
+                       if (win32_error (ciw, unitnum, L"IOCTL_CDROM_GET_DRIVE_GEOMETRY") < 0)
                                continue;
-                       reseterrormode (unitnum);
-                       uae_sem_post (&ciw32[unitnum].sub_sem);
+                       reseterrormode (ciw);
+                       uae_sem_post (&ciw->sub_sem);
                        return 0;
                }
+               break;
        }
-       reseterrormode (unitnum);
-       uae_sem_post (&ciw32[unitnum].sub_sem);
+       reseterrormode (ciw);
+       uae_sem_post (&ciw->sub_sem);
        if (di) {
                di->cylinders = geom.Cylinders.LowPart;
                di->sectorspertrack = geom.SectorsPerTrack;
@@ -803,40 +909,40 @@ static int fetch_geometry (int unitnum, struct device_info *di)
        return 1;
 }
 
-static int ismedia (int unitnum)
+static int ismedia (struct dev_info_ioctl *ciw, int unitnum)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-       return fetch_geometry (unitnum, &ciw->di);
+       return fetch_geometry (ciw, unitnum, &ciw->di);
 }
 
 /* read toc */
-static struct cd_toc_head *ioctl_command_toc (int unitnum)
+static int ioctl_command_toc (int unitnum, struct cd_toc_head *tocout)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
+               return 0;
+
        DWORD len;
        int i;
-       struct cd_toc_head *th = (struct cd_toc_head*)ciw->tempbuffer;
+       struct cd_toc_head *th = &ciw->di.toc;
        struct cd_toc *t = th->toc;
        int cnt = 3;
-       CDROM_TOC *toc = &ciw->toc;
+       CDROM_TOC *toc = &ciw->cdromtoc;
 
        if (!unitisopen (unitnum))
-               return NULL;
+               return 0;
 
-       if (!open_createfile (unitnum, 0))
+       if (!open_createfile (ciw, 0))
                return 0;
-       cdda_stop (unitnum);
-       ciw32[unitnum].cd_last_pos = 0;
        gui_flicker_led (LED_CD, unitnum, 1);
        while (cnt-- > 0) {
-               seterrormode (unitnum);
-               if (!DeviceIoControl (ciw32[unitnum].h, IOCTL_CDROM_READ_TOC, NULL, 0, toc, sizeof (CDROM_TOC), &len, NULL)) {
-                       reseterrormode (unitnum);
-                       if (win32_error (unitnum, L"IOCTL_CDROM_READ_TOC") < 0)
+               seterrormode (ciw);
+               if (!DeviceIoControl (ciw->h, IOCTL_CDROM_READ_TOC, NULL, 0, toc, sizeof (CDROM_TOC), &len, NULL)) {
+                       reseterrormode (ciw);
+                       if (win32_error (ciw, unitnum, L"IOCTL_CDROM_READ_TOC") < 0)
                                continue;
                        return 0;
                }
-               reseterrormode (unitnum);
+               reseterrormode (ciw);
                break;
        }
 
@@ -875,37 +981,39 @@ static struct cd_toc_head *ioctl_command_toc (int unitnum)
        t++;
 
        gui_flicker_led (LED_CD, unitnum, 1);
-       return th;
+       memcpy (tocout, th, sizeof (struct cd_toc_head));
+       return 1;
 }
 
 static void update_device_info (int unitnum)
 {
-       if (!unitcheck (unitnum))
+       struct dev_info_ioctl *ciw = unitcheck (unitnum);
+       if (!ciw)
                return;
-       struct device_info *di = &ciw32[unitnum].di;
+       struct device_info *di = &ciw->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))
+       _stprintf (di->mediapath, L"\\\\.\\%c:", ciw->drvletter);
+       if (fetch_geometry (ciw, 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));
+       ioctl_command_toc (unitnum, &di->toc);
+       di->removable = ciw->type == DRIVE_CDROM ? 1 : 0;
+       di->write_protected = ciw->type == DRIVE_CDROM ? 1 : 0;
+       di->type = ciw->type == DRIVE_CDROM ? INQ_ROMD : INQ_DASD;
+       di->unitnum = unitnum + 1;
+       _tcscpy (di->label, ciw->drvlettername);
 }
 
 /* open device level access to cd rom drive */
-static int sys_cddev_open (int unitnum)
+static int sys_cddev_open (struct dev_info_ioctl *ciw, int unitnum)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
-       ciw->cdda_volume = 0xffff;
+       uae_u8 inquiry[256];
+       ciw->cdda_volume[0] = 0x7fff;
+       ciw->cdda_volume[1] = 0x7fff;
        ciw->cdda_volume_main = currprefs.sound_volume;
        /* buffer must be page aligned for device access */
        ciw->tempbuffer = (uae_u8*)VirtualAlloc (NULL, IOCTL_DATA_BUFFER, MEM_COMMIT, PAGE_READWRITE);
@@ -913,19 +1021,44 @@ static int sys_cddev_open (int unitnum)
                write_log (L"IOCTL: failed to allocate buffer");
                return 1;
        }
-       if (!open_createfile (unitnum, 0)) {
+       _tcscpy (ciw->di.vendorid, L"UAE");
+       _stprintf (ciw->di.productid, L"SCSI CD%d IMG", unitnum);
+       _tcscpy (ciw->di.revision, L"0.1");
+       if (spti_inquiry (ciw, unitnum, inquiry)) {
+               char tmp[20];
+               TCHAR *s;
+               memcpy (tmp, inquiry + 8, 8);
+               tmp[8] = 0;
+               s = au (tmp);
+               _tcscpy (ciw->di.vendorid, s);
+               xfree (s);
+               memcpy (tmp, inquiry + 16, 16);
+               tmp[16] = 0;
+               s = au (tmp);
+               _tcscpy (ciw->di.productid, s);
+               xfree (s);
+               memcpy (tmp, inquiry + 32, 4);
+               tmp[4] = 0;
+               s = au (tmp);
+               _tcscpy (ciw->di.revision, s);
+               xfree (s);
+               close_createfile (ciw);
+       }
+       if (!open_createfile (ciw, 0)) {
                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);
+       update_device_info (unitnum);
+       ciw->open = true;
+       write_log (L"IOCTL: device '%s' (%s/%s/%s) opened succesfully (unit=%d,media=%d)\n",
+               ciw->devname, ciw->di.vendorid, ciw->di.productid, ciw->di.revision,
+               unitnum, ciw->di.media_inserted);
        return 0;
 error:
-       win32_error (unitnum, L"CreateFile");
+       win32_error (ciw, unitnum, L"CreateFile");
        VirtualFree (ciw->tempbuffer, 0, MEM_RELEASE);
        ciw->tempbuffer = NULL;
        CloseHandle (ciw->h);
@@ -934,139 +1067,170 @@ error:
 }
 
 /* close device handle */
-void sys_cddev_close (int unitnum)
+static void sys_cddev_close (struct dev_info_ioctl *ciw, int unitnum)
 {
-       struct dev_info_ioctl *ciw = &ciw32[unitnum];
-
-       if (!unitcheck (unitnum))
+       if (ciw->open == false)
                return;
-       cdda_stop (unitnum);
-       close_createfile (unitnum);
+       cdda_stop (ciw);
+       close_createfile (ciw);
        VirtualFree (ciw->tempbuffer, 0, MEM_RELEASE);
        ciw->tempbuffer = NULL;
        uae_sem_destroy (&ciw->sub_sem);
        uae_sem_destroy (&ciw->sub_sem2);
+       ciw->open = false;
+       write_log (L"IOCTL: device '%s' closed\n", ciw->devname, unitnum);
 }
 
-static int open_device (int unitnum)
+static int open_device (int unitnum, const TCHAR *ident)
 {
-       if (!unitcheck (unitnum))
+       struct dev_info_ioctl *ciw = NULL;
+       if (ident) {
+               for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+                       ciw = &ciw32[i];
+                       if (unittable[i] == 0 && ciw->drvletter != 0) {
+                               if (!_tcsicmp (ciw->drvlettername, ident)) {
+                                       unittable[unitnum] = i + 1;
+                                       if (sys_cddev_open (ciw, unitnum) == 0)
+                                               return 1;
+                                       unittable[unitnum] = 0;
+                                       return 0;
+                               }
+                       }
+               }
                return 0;
-       if (sys_cddev_open (unitnum) == 0)
+       }
+       ciw = &ciw32[unitnum];
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (unittable[i] == unitnum + 1)
+                       return 0;
+       }
+       if (ciw->drvletter == 0)
+               return 0;
+       unittable[unitnum] = unitnum + 1;
+       if (sys_cddev_open (ciw, unitnum) == 0)
                return 1;
+       unittable[unitnum] = 0;
        return 0;
 }
 static void close_device (int unitnum)
 {
-       sys_cddev_close (unitnum);
-}
-
-static void close_bus (void)
-{
+       struct dev_info_ioctl *ciw = unitcheck (unitnum);
+       if (!ciw)
+               return;
+       sys_cddev_close (ciw, unitnum);
+       unittable[unitnum] = 0;
 }
 
 static int total_devices;
 
-static int check_bus (int flags)
+static void close_bus (void)
 {
-       return 1;
+       if (!bus_open) {
+               write_log (L"IOCTL close_bus() when already closed!\n");
+               return;
+       }
+       total_devices = 0;
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               sys_cddev_close (&ciw32[i], i);
+               memset (&ciw32[i], 0, sizeof (struct dev_info_ioctl));
+               ciw32[i].h = INVALID_HANDLE_VALUE;
+               unittable[i] = 0;
+       }
+       bus_open = 0;
+       write_log (L"IOCTL driver closed.\n");
 }
 
 static int open_bus (int flags)
 {
        int dwDriveMask;
-       int drive, i;
-       TCHAR tmp[10];
+       int drive;
 
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               memset (&ciw32[i], 0, sizeof (struct dev_info_ioctl));
-               ciw32[i].h = INVALID_HANDLE_VALUE;
+       if (bus_open) {
+               write_log (L"IOCTL open_bus() more than once!\n");
+               return 1;
        }
-       MCICDA = 1;//os_vista ? 1 : 0;
        total_devices = 0;
        dwDriveMask = GetLogicalDrives ();
        if (log_scsi)
                write_log (L"IOCTL: drive mask = %08X\n", dwDriveMask);
        dwDriveMask >>= 2; // Skip A and B drives...
-       for (drive = 'C'; drive <= 'Z' && total_devices < MAX_TOTAL_DEVICES; drive++) {
+       for (drive = 'C'; drive <= 'Z' && total_devices < MAX_TOTAL_SCSI_DEVICES; drive++) {
                if (dwDriveMask & 1) {
                        int dt;
+                       TCHAR tmp[10];
                        _stprintf (tmp, L"%c:\\", drive);
                        dt = GetDriveType (tmp);
                        if (log_scsi)
                                write_log (L"IOCTL: drive %c type %d\n", drive, dt);
-                       if (((flags & (1 << INQ_ROMD)) && dt == DRIVE_CDROM) || ((flags & (1 << INQ_DASD)) && dt == DRIVE_FIXED)) {
+                       if (dt == DRIVE_CDROM) {
                                if (log_scsi)
                                        write_log (L"IOCTL: drive %c: = unit %d\n", drive, total_devices);
                                ciw32[total_devices].drvletter = drive;
                                _tcscpy (ciw32[total_devices].drvlettername, tmp);
                                ciw32[total_devices].type = dt;
-                               ciw32[total_devices].blocksize = 2048;
+                               ciw32[total_devices].di.bytespersector = 2048;
                                _stprintf (ciw32[total_devices].devname, L"\\\\.\\%c:", drive);
+                               ciw32[total_devices].h = INVALID_HANDLE_VALUE;
                                total_devices++;
                        }
                }
                dwDriveMask >>= 1;
        }
+       bus_open = 1;
+       write_log (L"IOCTL driver open, %d devices.\n", total_devices);
        return total_devices;
 }
 
 static int ioctl_ismedia (int unitnum, int quick)
 {
-       if (!unitcheck (unitnum))
-               return -1;
-       if (!unitisopen (unitnum))
+       struct dev_info_ioctl *ciw = unitisopen (unitnum);
+       if (!ciw)
                return -1;
        if (quick) {
-               struct dev_info_ioctl *ciw = &ciw32[unitnum];
-               return ciw->mediainserted;
+               return ciw->di.media_inserted;
        }
        update_device_info (unitnum);
-       return ismedia (unitnum);
+       return ismedia (ciw, unitnum);
 }
 
 static struct device_info *info_device (int unitnum, struct device_info *di, int quick)
 {
-       if (!unitcheck (unitnum))
+       struct dev_info_ioctl *ciw = unitcheck (unitnum);
+       if (!ciw)
                return 0;
        if (!quick)
                update_device_info (unitnum);
-       memcpy (di, &ciw32[unitnum].di, sizeof (struct device_info));
+       ciw->di.open = di->open;
+       memcpy (di, &ciw->di, sizeof (struct device_info));
        return di;
 }
 
 void win32_ioctl_media_change (TCHAR driveletter, int insert)
 {
-       int i;
-
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               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;
-                       update_device_info (i);
-                       scsi_do_disk_change (driveletter, insert, NULL);
+       for (int i = 0; i < total_devices; i++) {
+               struct dev_info_ioctl *ciw = &ciw32[i];
+               if (ciw->drvletter == driveletter && ciw->di.media_inserted != insert) {
+                       write_log (L"IOCTL: media change %s %d\n", ciw->drvlettername, insert);
+                       ciw->di.media_inserted = insert;
+                       int unitnum = getunitnum (ciw);
+                       if (unitnum >= 0) {
+                               update_device_info (unitnum);
+                               scsi_do_disk_change (unitnum, insert, NULL);
 #ifdef RETROPLATFORM
-                       rp_cd_image_change (i, ciw32[i].drvlettername);
+                               rp_cd_image_change (unitnum, ciw->drvlettername);
 #endif
+                       }
                }
        }
 }
 
-static struct device_scsi_info *ioctl_scsi_info (int unitnum, struct device_scsi_info *dsi)
-{
-       if (!unitcheck (unitnum))
-               return 0;
-       dsi->buffer = ciw32[unitnum].tempbuffer;
-       dsi->bufsize = IOCTL_DATA_BUFFER;
-       return dsi;
-}
-
 struct device_functions devicefunc_win32_ioctl = {
-       check_bus, open_bus, close_bus, open_device, close_device, info_device,
+       L"IOCTL",
+       open_bus, close_bus, open_device, close_device, info_device,
        0, 0, 0,
        ioctl_command_pause, ioctl_command_stop, ioctl_command_play, ioctl_command_volume, ioctl_command_qcode,
        ioctl_command_toc, ioctl_command_read, ioctl_command_rawread, ioctl_command_write,
-       0, ioctl_scsi_info, ioctl_ismedia
+       0, ioctl_ismedia
 };
 
 #endif
index e06a8813ac29ce06e385f1c2bfaaef160332f71d..d18999b4ee0f28fb3848ef6b0ebfafd855083632 100644 (file)
@@ -45,8 +45,6 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
        UCHAR SenseBuf[32];
 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
 
-static int unitcnt = 0;
-
 struct dev_info_spti {
        TCHAR *drvpath;
        TCHAR *name;
@@ -62,15 +60,54 @@ struct dev_info_spti {
        int bus, path, target, lun;
        int scanmode;
        uae_u8 *scsibuf;
+       bool open;
+       bool enabled;
+       struct device_info di;
 };
 
 static uae_sem_t scgp_sem;
-static struct dev_info_spti dev_info[MAX_TOTAL_DEVICES];
+static struct dev_info_spti dev_info[MAX_TOTAL_SCSI_DEVICES];
+static int unittable[MAX_TOTAL_SCSI_DEVICES];
+static int total_devices;
+static int bus_open;
+
+static int getunitnum (struct dev_info_spti *di)
+{
+       if (!di)
+               return -1;
+       int idx = di - &dev_info[0];
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (unittable[i] - 1 == idx)
+                       return i;
+       }
+       return -1;
+}
+
+static struct dev_info_spti *unitcheck (int unitnum)
+{
+       if (unitnum < 0 || unitnum >= MAX_TOTAL_SCSI_DEVICES)
+               return NULL;
+       if (unittable[unitnum] <= 0)
+               return NULL;
+       unitnum = unittable[unitnum] - 1;
+       if (dev_info[unitnum].drvletter == 0)
+               return NULL;
+       return &dev_info[unitnum];
+}
+
+static struct dev_info_spti *unitisopen (int unitnum)
+{
+       struct dev_info_spti *di = unitcheck (unitnum);
+       if (!di)
+               return NULL;
+       if (di->open == false)
+               return NULL;
+       return di;
+}
 
-static int doscsi (int unitnum, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *swb, int *err)
+static int doscsi (struct dev_info_spti *di, int unitnum, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *swb, int *err)
 {
        DWORD status, returned;
-       struct dev_info_spti *di = &dev_info[unitnum];
 
        *err = 0;
        if (log_scsi) {
@@ -114,7 +151,7 @@ static int doscsi (int unitnum, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *swb, int *
 #define MODE_SELECT_10 0x55
 #define MODE_SENSE_10  0x5A
 
-static int execscsicmd (int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int inlen)
+static int execscsicmd (struct dev_info_spti *di, int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int inlen)
 {
        SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
        DWORD status;
@@ -136,7 +173,7 @@ static int execscsicmd (int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int i
        swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
        swb.spt.SenseInfoLength = 32;
        memcpy (swb.spt.Cdb, data, len);
-       status = doscsi (unitnum, &swb, &err);
+       status = doscsi (di, unitnum, &swb, &err);
        uae_sem_post (&scgp_sem);
        dolen = swb.spt.DataTransferLength;
        if (!status)
@@ -146,6 +183,10 @@ static int execscsicmd (int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int i
 
 static int execscsicmd_direct (int unitnum, struct amigascsi *as)
 {
+       struct dev_info_spti *di = unitisopen (unitnum);
+       if (!di)
+               return -1;
+
        SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
        DWORD status;
        int sactual = 0, i;
@@ -176,7 +217,7 @@ static int execscsicmd_direct (int unitnum, struct amigascsi *as)
        swb.spt.DataTransferLength = as->len;
        swb.spt.DataBuffer = scsi_datap;
 
-       status = doscsi (unitnum, &swb, &err);
+       status = doscsi (di, unitnum, &swb, &err);
 
        as->cmdactual = status == 0 ? 0 : scsi_cmd_len_orig; /* fake scsi_CmdActual */
        as->status = swb.spt.ScsiStatus; /* scsi_Status */
@@ -213,7 +254,10 @@ static int execscsicmd_direct (int unitnum, struct amigascsi *as)
 
 static uae_u8 *execscsicmd_out (int unitnum, uae_u8 *data, int len)
 {
-       int v = execscsicmd (unitnum, data, len, 0, 0);
+       struct dev_info_spti *di = unitisopen (unitnum);
+       if (!di)
+               return 0;
+       int v = execscsicmd (di, unitnum, data, len, 0, 0);
        if (v < 0)
                return 0;
        return data;
@@ -221,73 +265,162 @@ static uae_u8 *execscsicmd_out (int unitnum, uae_u8 *data, int len)
 
 static uae_u8 *execscsicmd_in (int unitnum, uae_u8 *data, int len, int *outlen)
 {
-       int v = execscsicmd (unitnum, data, len, dev_info[unitnum].scsibuf, DEVICE_SCSI_BUFSIZE);
+       struct dev_info_spti *di = unitisopen (unitnum);
+       if (!di)
+               return 0;
+       int v = execscsicmd (di, unitnum, data, len, di->scsibuf, DEVICE_SCSI_BUFSIZE);
        if (v < 0)
                return 0;
        if (v == 0)
                return 0;
        if (outlen)
                *outlen = v;
-       return dev_info[unitnum].scsibuf;
+       return di->scsibuf;
 }
 
-static int total_devices;
+static uae_u8 *execscsicmd_in_internal (struct dev_info_spti *di, int unitnum, uae_u8 *data, int len, int *outlen)
+{
+       int v = execscsicmd (di, unitnum, data, len, di->scsibuf, DEVICE_SCSI_BUFSIZE);
+       if (v < 0)
+               return 0;
+       if (v == 0)
+               return 0;
+       if (outlen)
+               *outlen = v;
+       return di->scsibuf;
+}
 
+static void close_scsi_device2 (struct dev_info_spti *di)
+{
+       if (di->open == false)
+               return;
+       if (di->handle != INVALID_HANDLE_VALUE)
+               CloseHandle (di->handle);
+       di->handle = INVALID_HANDLE_VALUE;
+       di->open = false;
+}
 
 static void close_scsi_device (int unitnum)
 {
-       if (dev_info[unitnum].handle != INVALID_HANDLE_VALUE) {
-               write_log (L"SPTI: unit %d closed\n", unitnum);
-               CloseHandle (dev_info[unitnum].handle);
-       }
-       dev_info[unitnum].handle = INVALID_HANDLE_VALUE;
+       struct dev_info_spti *di = unitisopen (unitnum);
+       if (!di)
+               return;
+       close_scsi_device2 (di);
+       unittable[unitnum] = 0;
 }
 
-static void free_scsi_device(int dev)
+static void free_scsi_device (struct dev_info_spti *di)
 {
-       close_scsi_device (dev);
-       xfree(dev_info[dev].name);
-       xfree(dev_info[dev].drvpath);
-       xfree(dev_info[dev].inquirydata);
-       VirtualFree (dev_info[dev].scsibuf, 0, MEM_RELEASE);
-       dev_info[dev].name = NULL;
-       dev_info[dev].drvpath = NULL;
-       dev_info[dev].inquirydata = NULL;
-       dev_info[dev].scsibuf = NULL;
-       memset(&dev_info[dev], 0, sizeof (struct dev_info_spti));
+       close_scsi_device2 (di);
+       xfree (di->name);
+       xfree (di->drvpath);
+       xfree (di->inquirydata);
+       VirtualFree (di->scsibuf, 0, MEM_RELEASE);
+       di->name = NULL;
+       di->drvpath = NULL;
+       di->inquirydata = NULL;
+       di->scsibuf = NULL;
+       memset (di, 0, sizeof (struct dev_info_spti));
 }
 
 static int rescan (void);
 
-static int check_scsi_bus (int flags)
+static void close_scsi_bus (void)
 {
-       return 1;
+       if (!bus_open) {
+               write_log (L"SPTI close_bus() when already closed!\n");
+               return;
+       }
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               free_scsi_device (&dev_info[i]);
+               unittable[i] = 0;
+       }
+       total_devices = 0;
+       bus_open = 0;
+       write_log (L"SPTI driver closed.\n");
 }
 
 static int open_scsi_bus (int flags)
 {
-       int i;
-
+       if (bus_open) {
+               write_log (L"SPTI open_bus() more than once!\n");
+               return 1;
+       }
        total_devices = 0;
        uae_sem_init (&scgp_sem, 0, 1);
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               memset (&dev_info[i], 0, sizeof (struct dev_info_spti));
-               dev_info[i].handle = INVALID_HANDLE_VALUE;
-       }
        rescan ();
+       bus_open = 1;
+       write_log (L"SPTI driver open, %d devices.\n", total_devices);
        return total_devices;
 }
 
-static void close_scsi_bus (void)
+static int mediacheck (struct dev_info_spti *di, int unitnum)
+{
+       uae_u8 cmd [6] = { 0,0,0,0,0,0 }; /* TEST UNIT READY */
+       if (di->open == false)
+               return -1;
+       int v = execscsicmd (di, unitnum, cmd, sizeof cmd, 0, 0);
+       return v >= 0 ? 1 : 0;
+}
+
+static int mediacheck_full (struct dev_info_spti *di, int unitnum, struct device_info *dinfo)
 {
-       int i;
-       for (i = 0; i < total_devices; i++)
-               free_scsi_device (i);
+       uae_u8 cmd1[10] = { 0x25,0,0,0,0,0,0,0,0,0 }; /* READ CAPACITY */
+       uae_u8 *p;
+       int outlen;
+
+       dinfo->sectorspertrack = 0;
+       dinfo->trackspercylinder = 0;
+       dinfo->bytespersector = 0;
+       dinfo->cylinders = 0;
+       dinfo->write_protected = 1;
+       if (di->open == false)
+               return 0;
+       outlen = 32;
+       p = execscsicmd_in_internal (di, unitnum, cmd1, sizeof cmd1, &outlen);
+       if (p && outlen >= 8) {
+               dinfo->bytespersector = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
+               dinfo->sectorspertrack = ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + 1;
+               dinfo->trackspercylinder = 1;
+               dinfo->cylinders = 1;
+       }
+       if (di->type == INQ_DASD) {
+               uae_u8 cmd2[10] = { 0x5a,0x08,0,0,0,0,0,0,0xf0,0 }; /* MODE SENSE */
+               outlen = 32;
+               p = execscsicmd_in_internal (di, unitnum, cmd2, sizeof cmd2, &outlen);
+               if (p && outlen >= 4) {
+                       dinfo->write_protected = (p[3] & 0x80) ? 1 : 0;
+               }
+       }
+       //      write_log (L"mediacheck_full(%d,%d,%d,%d,%d)\n",
+       //      di->bytespersector, di->sectorspertrack, di->trackspercylinder, di->cylinders, di->write_protected);
+       return 1;
+}
+
+static void update_device_info (int unitnum)
+{
+       struct dev_info_spti *dispti = unitisopen (unitnum);
+       if (!dispti)
+               return;
+       struct device_info *di = &dispti->di;
+       _tcscpy (di->label, dispti->drvletter ? dispti->drvlettername : dispti->name);
+       _tcscpy (di->mediapath, dispti->drvpath);
+       di->bus = 0;
+       di->target = unitnum;
+       di->lun = 0;
+       di->media_inserted = mediacheck (dispti, unitnum);
+       di->removable = dispti->removable;
+       mediacheck_full (dispti, unitnum, di);
+       di->type = dispti->type;
+       di->unitnum = unitnum + 1;
+       if (log_scsi) {
+               write_log (L"MI=%d TP=%d WP=%d CY=%d BK=%d RMB=%d '%s'\n",
+                       di->media_inserted, di->type, di->write_protected, di->cylinders, di->bytespersector, di->removable, di->label);
+       }
 }
 
-static void checkcapabilities (int unitnum)
+static void checkcapabilities (struct dev_info_spti *di)
 {
-       struct dev_info_spti *di = &dev_info[unitnum];
        STORAGE_ADAPTER_DESCRIPTOR desc;
        STORAGE_PROPERTY_QUERY query;
        DWORD ret, status;
@@ -304,12 +437,12 @@ static void checkcapabilities (int unitnum)
        }
 }
 
-static int inquiry (int unitnum, struct dev_info_spti *di, uae_u8 *inquirydata)
+static int inquiry (struct dev_info_spti *di, int unitnum, uae_u8 *inquirydata)
 {
        uae_u8 cmd[6] = { 0x12,0,0,0,36,0 }; /* INQUIRY */
        uae_u8 out[INQUIRY_SIZE] = { 0 };
        int outlen = sizeof (out);
-       uae_u8 *p = execscsicmd_in (unitnum, cmd, sizeof (cmd), &outlen);
+       uae_u8 *p = execscsicmd_in_internal (di, unitnum, cmd, sizeof (cmd), &outlen);
        int inqlen = 0;
 
        di->isatapi = 0;
@@ -348,61 +481,11 @@ static int inquiry (int unitnum, struct dev_info_spti *di, uae_u8 *inquirydata)
        return inqlen;
 }
 
-static int mediacheck (int unitnum)
-{
-       uae_u8 cmd [6] = { 0,0,0,0,0,0 }; /* TEST UNIT READY */
-       int v;
-       if (dev_info[unitnum].handle == INVALID_HANDLE_VALUE)
-               return 0;
-       v = execscsicmd (unitnum, cmd, sizeof (cmd), 0, 0);
-       return v >= 0 ? 1 : 0;
-}
-
-static int mediacheck_full (int unitnum, struct device_info *di)
-{
-       uae_u8 cmd1[10] = { 0x25,0,0,0,0,0,0,0,0,0 }; /* READ CAPACITY */
-       uae_u8 *p;
-       int outlen;
-
-       di->sectorspertrack = 0;
-       di->trackspercylinder = 0;
-       di->bytespersector = 0;
-       di->cylinders = 0;
-       di->write_protected = 1;
-       if (dev_info[unitnum].handle == INVALID_HANDLE_VALUE)
-               return 0;
-       outlen = 32;
-       p = execscsicmd_in (unitnum, cmd1, sizeof cmd1, &outlen);
-       if (p && outlen >= 8) {
-               di->bytespersector = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
-               di->sectorspertrack = ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + 1;
-               di->trackspercylinder = 1;
-               di->cylinders = 1;
-       }
-       if (di->type == INQ_DASD) {
-               uae_u8 cmd2[10] = { 0x5a,0x08,0,0,0,0,0,0,0xf0,0 }; /* MODE SENSE */
-               outlen = 32;
-               p = execscsicmd_in (unitnum, cmd2, sizeof cmd2, &outlen);
-               if (p && outlen >= 4) {
-                       di->write_protected = (p[3] & 0x80) ? 1 : 0;
-               }
-       }
-       //    write_log (L"mediacheck_full(%d,%d,%d,%d,%d)\n",
-       //      di->bytespersector, di->sectorspertrack, di->trackspercylinder, di->cylinders, di->write_protected);
-       return 1;
-}
-
-int open_scsi_device (int unitnum)
+static int open_scsi_device2 (struct dev_info_spti *di, int unitnum)
 {
        HANDLE h;
        TCHAR *dev;
-       struct dev_info_spti *di;
 
-       di = &dev_info[unitnum];
-       if (unitnum >= total_devices)
-               return 0;
-       if (!di)
-               return 0;
        if (di->bus >= 0) {
                dev = xmalloc (TCHAR, 100);
                _stprintf (dev, L"\\\\.\\Scsi%d:", di->bus);
@@ -417,18 +500,18 @@ int open_scsi_device (int unitnum)
                write_log (L"SPTI: failed to open unit %d err=%d ('%s')\n", unitnum, GetLastError (), dev);
        } else {
                uae_u8 inqdata[INQUIRY_SIZE + 1] = { 0 };
-               checkcapabilities (unitnum);
-               if (!inquiry (unitnum, di, inqdata)) {
+               checkcapabilities (di);
+               if (!inquiry (di, unitnum, inqdata)) {
                        write_log (L"SPTI: inquiry failed unit %d ('%s':%d:%d:%d:%d)\n", unitnum, dev,
                                di->bus, di->path, di->target, di->lun);
-                       close_scsi_device (unitnum);
+                       close_scsi_device2 (di);
                        xfree (dev);
                        return 0;
                }
                inqdata[INQUIRY_SIZE] = 0;
                di->name = my_strdup_ansi ((char*)inqdata + 8);
                if (di->type == INQ_ROMD) {
-                       dev_info[unitnum].mediainserted = mediacheck (unitnum);
+                       di->mediainserted = mediacheck (di, unitnum);
                        write_log (L"SPTI: unit %d (%c:\\) opened [%s], %s, '%s'\n",
                                unitnum, di->drvletter ? di->drvletter : '*',
                                di->isatapi ? L"ATAPI" : L"SCSI",
@@ -441,19 +524,52 @@ int open_scsi_device (int unitnum)
                di->inquirydata = xmalloc (uae_u8, INQUIRY_SIZE);
                memcpy (di->inquirydata, inqdata, INQUIRY_SIZE);
                xfree (dev);
+               update_device_info (unitnum);
+               di->open = true;
                return 1;
        }
        xfree (dev);
        return 0;
 }
+int open_scsi_device (int unitnum, const TCHAR *ident)
+{
+       struct dev_info_spti *di = NULL;
+       if (ident) {
+               for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+                       di = &dev_info[i];
+                       if (unittable[i] == 0 && di->drvletter != 0) {
+                               if (!_tcsicmp (di->drvlettername, ident)) {
+                                       unittable[unitnum] = i + 1;
+                                       if (open_scsi_device2 (di, unitnum))
+                                               return 1;
+                                       unittable[unitnum] = 0;
+                                       return 0;
+                               }
+                       }
+               }
+               return 0;
+       }
+       di = &dev_info[unitnum];
+       for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (unittable[i] == unitnum + 1)
+                       return 0;
+       }
+       if (di->enabled == 0)
+               return 0;
+       unittable[unitnum] = unitnum + 1;
+       if (open_scsi_device2 (di, unitnum))
+               return 1;
+       unittable[unitnum] = 0;
+       return 0;
+}
 
-static int adddrive (TCHAR *drvpath, int bus, int pathid, int targetid, int lunid, int scanmode)
+static int adddrive (const TCHAR *drvpath, int bus, int pathid, int targetid, int lunid, int scanmode)
 {
        struct dev_info_spti *di;
        int cnt = total_devices, i;
        int freeit = 1;
 
-       if (cnt >= MAX_TOTAL_DEVICES)
+       if (cnt >= MAX_TOTAL_SCSI_DEVICES)
                return 0;
        for (i = 0; i < total_devices; i++) {
                di = &dev_info[i];
@@ -470,6 +586,7 @@ static int adddrive (TCHAR *drvpath, int bus, int pathid, int targetid, int luni
        di->lun = lunid;
        di->scanmode = scanmode;
        di->drvletter = 0;
+       di->enabled = true;
 
        for (TCHAR drvletter = 'C'; drvletter <= 'Z'; drvletter++) {
                TCHAR drvname[10];
@@ -490,7 +607,8 @@ static int adddrive (TCHAR *drvpath, int bus, int pathid, int targetid, int luni
 
 
        total_devices++;
-       if (open_scsi_device (cnt)) {
+       unittable[cnt] = cnt + 1;
+       if (open_scsi_device2 (&dev_info[cnt], cnt)) {
                for (i = 0; i < cnt; i++) {
                        if (!memcmp (di->inquirydata, dev_info[i].inquirydata, INQUIRY_SIZE) && di->scanmode != dev_info[i].scanmode) {
                                write_log (L"duplicate device, skipped..\n");
@@ -499,57 +617,42 @@ static int adddrive (TCHAR *drvpath, int bus, int pathid, int targetid, int luni
                }
                if (i == cnt) {
                        freeit = 0;
-                       close_scsi_device (cnt);
+                       close_scsi_device2 (&dev_info[cnt]);
                }
        }
        if (freeit) {
-               free_scsi_device (cnt);
+               free_scsi_device (&dev_info[cnt]);
                total_devices--;
        }
+       unittable[cnt] = 0;
        return 1;
 }
 
-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, int quick)
 {
-       struct dev_info_spti *dispti;
-       if (unitnum >= MAX_TOTAL_DEVICES || dev_info[unitnum].handle == INVALID_HANDLE_VALUE)
+       struct dev_info_spti *dispti = unitcheck (unitnum);
+       if (!dispti)
                return NULL;
-       dispti = &dev_info[unitnum];
-       _tcscpy (di->label, dispti->drvletter ? dispti->drvlettername : dispti->name);
-       _tcscpy (di->mediapath, dispti->drvpath);
-       di->bus = 0;
-       di->target = unitnum;
-       di->lun = 0;
-       di->media_inserted = mediacheck (unitnum);
-       di->removable = dispti->removable;
-       mediacheck_full (unitnum, di);
-       di->type = dispti->type;
-       di->id = getid (unitnum);
-       if (log_scsi) {
-               write_log (L"MI=%d TP=%d WP=%d CY=%d BK=%d RMB=%d '%s'\n",
-                       di->media_inserted, di->type, di->write_protected, di->cylinders, di->bytespersector, di->removable, di->label);
-       }
+       if (!quick)
+               update_device_info (unitnum);
+       dispti->di.open = di->open;
+       memcpy (di, &dispti->di, sizeof (struct device_info));
        return di;
 }
 
 void win32_spti_media_change (TCHAR driveletter, int insert)
 {
-       int i, now;
-
-       for (i = 0; i < total_devices; i++) {
-               if (dev_info[i].type == INQ_ROMD) {
-                       now = mediacheck (i);
-                       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, NULL);
+       for (int i = 0; i < total_devices; i++) {
+               struct dev_info_spti *di = &dev_info[i];
+               if (di->drvletter == driveletter && di->mediainserted != insert) {
+                       write_log (L"SPTI: media change %c %d\n", dev_info[i].drvletter, insert);
+                       di->mediainserted = insert;
+                       int unitnum = getunitnum (di);
+                       if (unitnum >= 0) {
+                               update_device_info (unitnum);
+                               scsi_do_disk_change (unitnum, insert, NULL);
 #ifdef RETROPLATFORM
-                               rp_cd_image_change (i, dev_info[i].drvletter ? dev_info[i].drvlettername : dev_info[i].name);
+                               rp_cd_image_change (unitnum, di->drvletter ? di->drvlettername : di->name);
 #endif
                        }
                }
@@ -558,22 +661,12 @@ void win32_spti_media_change (TCHAR driveletter, int insert)
 
 static int check_isatapi (int unitnum)
 {
-       return dev_info[unitnum].isatapi;
-}
-
-static struct device_scsi_info *scsi_info (int unitnum, struct device_scsi_info *dsi)
-{
-       dsi->buffer = dev_info[unitnum].scsibuf;
-       dsi->bufsize = DEVICE_SCSI_BUFSIZE;
-       return dsi;
+       struct dev_info_spti *di = unitcheck (unitnum);
+       if (!di)
+               return 0;
+       return di->isatapi;
 }
 
-struct device_functions devicefunc_win32_spti = {
-       check_scsi_bus, open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device,
-       execscsicmd_out, execscsicmd_in, execscsicmd_direct,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, check_isatapi, scsi_info, 0
-};
-
 static int getCDROMProperty (int idx, HDEVINFO DevInfo, const GUID *guid)
 {
        SP_DEVICE_INTERFACE_DATA interfaceData;
@@ -769,3 +862,11 @@ static int rescan (void)
 
 
 #endif
+
+
+struct device_functions devicefunc_win32_spti = {
+       L"SPTI",
+       open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device,
+       execscsicmd_out, execscsicmd_in, execscsicmd_direct,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, check_isatapi, 0
+};
index 7cbe44a86f9e4727435fe068f977a880053a17be..fac2e5d8a5e7cf98d9ae7120c719db5abd8710ba 100644 (file)
@@ -908,8 +908,6 @@ static int initialize_rawinput (void)
                        } else if (did == di_keyboard) {
                                if (rdpdevice (buf))
                                        continue;
-                               if (rnum_kb < 2)
-                                       continue;
                                if (num_keyboard >= MAX_INPUT_DEVICES)
                                        continue;
                                did += num_keyboard;
@@ -985,7 +983,7 @@ static int initialize_rawinput (void)
        if (rnum_kb     && num_keyboard < MAX_INPUT_DEVICES - 1) {
                struct didata *did = di_keyboard + num_keyboard;
                num_keyboard++;
-               rkb++;
+               rnum_kb++;
                did->name = my_strdup (L"WinUAE null keyboard");
                did->rawinput = NULL;
                did->connection = DIDC_RAW;
@@ -1196,9 +1194,15 @@ static void handle_rawinput_2 (RAWINPUT *raw)
                        }
                }
                if (num == num_keyboard) {
-                       if (!istest && scancode == DIK_F12 && pressed && isfocus ())
-                               inputdevice_add_inputcode (AKS_ENTERGUI, 1);
-                       return;
+                       for (num = 0; num < num_keyboard; num++) {
+                               if (did->connection == DIDC_RAW && did->acquired && did->rawinput == NULL)
+                                       break;
+                       }
+                       if (num == num_keyboard) {
+                               if (!istest && scancode == DIK_F12 && pressed && isfocus ())
+                                       inputdevice_add_inputcode (AKS_ENTERGUI, 1);
+                               return;
+                       }
                }
 
                if (rawkeystate[scancode] == pressed) {
index be2c8e65e8751bdc7d598b6e767b797d66754f2e..20f3e3901212ac9c815844fd13cbe4067c6dc09d 100644 (file)
@@ -394,7 +394,7 @@ int my_getvolumeinfo (const TCHAR *root)
                DWORD comlen;
                DWORD flags;
                if (GetVolumeInformation (volume, NULL, 0, NULL, &comlen, &flags, fsname, sizeof (fsname))) {
-                       write_log (L"Volume %s FS=%s maxlen=%d flags=%08X\n", volume, fsname, comlen, flags);
+                       //write_log (L"Volume %s FS=%s maxlen=%d flags=%08X\n", volume, fsname, comlen, flags);
                        if (flags & FILE_NAMED_STREAMS)
                                ret |= MYVOLUMEINFO_STREAMS;
                }
index f56d355306307e08973b43af3a101213899f4af0..12601e6885724e5fade05a0d11e125f7646cae7e 100644 (file)
@@ -281,7 +281,7 @@ int uae_start_thread (TCHAR *name, void *(*f)(void *), void *arg, uae_thread_id
        hThread = (HANDLE)_beginthreadex (NULL, 0, thread_init, thp, 0, &foo);
        if (hThread) {
                if (name) {
-                       write_log (L"Thread '%s' started (%d)\n", name, hThread);
+                       //write_log (L"Thread '%s' started (%d)\n", name, hThread);
                        SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
                }
        } else {
index 9c5aa3bb52dcc97af82ff0a8691143c28e0ec3bf..1457b0f0f2b76a45827273e79f768fd3743490b7 100644 (file)
@@ -196,7 +196,7 @@ static int cd_insert (int num, const TCHAR *name)
 {
        if (num != 0)
                return 0;
-       _tcscpy (changed_prefs.cdimagefile, name);
+       _tcscpy (changed_prefs.cdimagefile[0], name);
        config_changed = 1;
        return 1;
 }
@@ -834,17 +834,17 @@ void rp_fixup_options (struct uae_prefs *p)
                }
        }
 
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               int v = sys_command_ismedia (DF_IOCTL, i, 1);
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               int v = sys_command_ismedia (i, 1);
                if (v >= 0)
                        cd_mask |= 1 << i;
        }
        RPSendMessagex (RPIPCGM_DEVICES, RP_DEVICE_CD, cd_mask, NULL, 0, &guestinfo, NULL);
        if (cd_mask) {
-               for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+               for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                        if ((1 << i) & cd_mask) {
                                struct device_info di = { 0 };
-                               if (sys_command_info (DF_IOCTL, i, &di, 0))
+                               if (sys_command_info (i, &di, 0))
                                        rp_cd_image_change (i, di.mediapath);
                        }
                }
index acef1a91fb2e053b53e548584083692371f6d34c..11b16e85ec33712fde9421d9b80582d49c4897c2 100644 (file)
@@ -2139,17 +2139,13 @@ extern const TCHAR *get_aspi_path (int);
 
 static int get_aspi (int old)
 {
-       if ((old == UAESCSI_SPTI || old == UAESCSI_SPTISCAN) && os_winnt_admin)
-               return old;
        if (old == UAESCSI_NEROASPI && get_aspi_path (1))
                return old;
        if (old == UAESCSI_FROGASPI && get_aspi_path (2))
                return old;
        if (old == UAESCSI_ADAPTECASPI && get_aspi_path (0))
                return old;
-       if (os_winnt_admin)
-               return UAESCSI_SPTI;
-       else if (get_aspi_path (1))
+       if (get_aspi_path (1))
                return UAESCSI_NEROASPI;
        else if (get_aspi_path (2))
                return UAESCSI_FROGASPI;
@@ -2508,7 +2504,7 @@ void target_default_options (struct uae_prefs *p, int type)
                p->win32_automount_cddrives = 0;
                p->win32_automount_netdrives = 0;
                p->win32_kbledmode = 0;
-               p->win32_uaescsimode = get_aspi (p->win32_uaescsimode);
+               p->win32_uaescsimode = UAESCSI_CDEMU;
                p->win32_borderless = 0;
                p->win32_powersavedisabled = 1;
                p->sana2 = 0;
@@ -2521,7 +2517,7 @@ void target_default_options (struct uae_prefs *p, int type)
                p->win32_commandpathend[0] = 0;
        }
        if (type == 1 || type == 0) {
-               p->win32_uaescsimode = get_aspi (p->win32_uaescsimode);
+               p->win32_uaescsimode = UAESCSI_CDEMU;
                p->win32_midioutdev = -2;
                p->win32_midiindev = 0;
                p->win32_automount_removable = 0;
@@ -2726,7 +2722,7 @@ int target_parse_option (struct uae_prefs *p, TCHAR *option, TCHAR *value)
        }
 
        if (cfgfile_yesno (option, value, L"aspi", &vb)) {
-               p->win32_uaescsimode = false;
+               p->win32_uaescsimode = 0;
                if (vb)
                        p->win32_uaescsimode = get_aspi (0);
                if (p->win32_uaescsimode < UAESCSI_ASPI_FIRST)
@@ -2770,8 +2766,11 @@ int target_parse_option (struct uae_prefs *p, TCHAR *option, TCHAR *value)
                return 1;
        }
 
-       if (cfgfile_strval (option, value, L"uaescsimode", &p->win32_uaescsimode, scsimode, 0))
+       if (cfgfile_strval (option, value, L"uaescsimode", &p->win32_uaescsimode, scsimode, 0)) {
+               // do not forget me!
+               p->win32_uaescsimode = UAESCSI_CDEMU;
                return 1;
+       }
 
        if (cfgfile_intval (option, value, L"active_priority", &v, 1)) {
                p->win32_active_priority = fetchpri (v, 1);
index 360b149d652afc4d235f1133a40f6c4d508114c7..a999f03602ef42d07594242c2ce8cd1986db2365 100644 (file)
@@ -18,8 +18,8 @@
 #define WINUAEPUBLICBETA 1
 #define LANG_DLL 1
 
-#define WINUAEBETA L"3"
-#define WINUAEDATE MAKEBD(2010, 7, 16)
+#define WINUAEBETA L"4"
+#define WINUAEDATE MAKEBD(2010, 7, 18)
 #define WINUAEEXTRA L""
 #define WINUAEREV L""
 
index 9d29c0588590466ea6514e335d430638a9d2f365..8b7b0b5c89b0bda0a653084063275845ab060a9d 100644 (file)
@@ -1922,15 +1922,15 @@ static UINT_PTR CALLBACK ofnhook (HWND hDlg, UINT message, WPARAM wParam, LPARAM
 
 static void eject_cd (void)
 {
-       workprefs.cdimagefile[0] = 0;
+       workprefs.cdimagefile[0][0] = 0;
        quickstart_cddrive[0] = 0;
-       workprefs.cdimagefileuse = false;
+       workprefs.cdimagefileuse[0] = false;
        if (full_property_sheet) {
                quickstart_cdtype = 0;
        } else {
                if (quickstart_cdtype > 0) {
                        quickstart_cdtype = 1;
-                       workprefs.cdimagefileuse = true;
+                       workprefs.cdimagefileuse[0] = true;
                }
        }
 }
@@ -1949,7 +1949,7 @@ static void selectcd (struct uae_prefs *prefs, HWND hDlg, int num, int id, TCHAR
        SetDlgItemText (hDlg, id, full_path);
        if (quickstart_cddrive[0])
                eject_cd ();
-       _tcscpy (prefs->cdimagefile, full_path);
+       _tcscpy (prefs->cdimagefile[0], full_path);
        DISK_history_add (full_path, -1, HISTORY_CD, 0);
 }
 
@@ -4810,8 +4810,8 @@ static void init_quickstartdlg (HWND hDlg)
                        workprefs.df[1][0] = 0;
                        workprefs.df[2][0] = 0;
                        workprefs.df[3][0] = 0;
-                       workprefs.cdimagefile[0] = 0;
-                       workprefs.cdimagefileuse = quickstart_cdtype > 0;
+                       workprefs.cdimagefile[0][0] = 0;
+                       workprefs.cdimagefileuse[0] = quickstart_cdtype > 0;
                        load_quickstart (hDlg, 1);
                        quickstarthost (hDlg, hostconf);
                }
@@ -5054,11 +5054,12 @@ static INT_PTR CALLBACK QuickstartDlgProc (HWND hDlg, UINT msg, WPARAM wParam, L
                                                int len = sizeof quickstart_cddrive / sizeof (TCHAR);
                                                quickstart_cdtype = 2;
                                                SendDlgItemMessage (hDlg, IDC_CD0Q_TYPE, WM_GETTEXT, (WPARAM)len, (LPARAM)quickstart_cddrive);
-                                               _tcscpy (workprefs.cdimagefile, quickstart_cddrive);
+                                               _tcscpy (workprefs.cdimagefile[0], quickstart_cddrive);
                                        } else {
                                                eject_cd ();
                                                quickstart_cdtype = val;
                                        }
+                                       workprefs.cdimagefileuse[0] = quickstart_cdtype > 0;
                                        addfloppytype (hDlg, 1);
                                        addfloppyhistory (hDlg);
                                }
@@ -7210,8 +7211,8 @@ 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"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)"));
@@ -8382,7 +8383,6 @@ static struct fsvdlg_vals current_fsvdlg;
 
 struct hfdlg_vals
 {
-       TCHAR volumename[MAX_DPATH];
        TCHAR devicename[MAX_DPATH];
        TCHAR filename[MAX_DPATH];
        TCHAR fsfilename[MAX_DPATH];
@@ -8400,7 +8400,7 @@ struct hfdlg_vals
        bool original;
 };
 
-static struct hfdlg_vals empty_hfdlg = { L"", L"", L"", L"", 32, 2, 1, 0, 512, 1, 0, 0, 0, 1, 0, 1 };
+static struct hfdlg_vals empty_hfdlg = { L"", L"", L"", 32, 2, 1, 0, 512, 1, 0, 0, 0, 1, 0, 1 };
 static struct hfdlg_vals current_hfdlg;
 static int archivehd;
 
@@ -9102,7 +9102,7 @@ static void harddiskdlg_button (HWND hDlg, WPARAM wParam)
        case IDC_CD_SELECT:
                DiskSelection (hDlg, wParam, 17, &workprefs, NULL);
                quickstart_cdtype = 1;
-               workprefs.cdimagefileuse = true;
+               workprefs.cdimagefileuse[0] = true;
                addcdtype (hDlg, IDC_CD_TYPE);
                break;
        case IDC_CD_EJECT:
@@ -9278,7 +9278,7 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                        case IDC_CD_TEXT:
                        getfloppyname (hDlg, 0, 1, IDC_CD_TEXT);
                        quickstart_cdtype = 1;
-                       workprefs.cdimagefileuse = true;
+                       workprefs.cdimagefileuse[0] = true;
                        addcdtype (hDlg, IDC_CD_TYPE);
                        addfloppyhistory_2 (hDlg, 0, IDC_CD_TEXT, HISTORY_CD);
                        break;
@@ -9289,14 +9289,14 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                                if (quickstart_cdtype >= 2) {
                                        int len = sizeof quickstart_cddrive / sizeof (TCHAR);
                                        quickstart_cdtype = 2;
-                                       workprefs.cdimagefileuse = true;
+                                       workprefs.cdimagefileuse[0] = true;
                                        SendDlgItemMessage (hDlg, IDC_CD_TYPE, WM_GETTEXT, (WPARAM)len, (LPARAM)quickstart_cddrive);
-                                       _tcscpy (workprefs.cdimagefile, quickstart_cddrive);
+                                       _tcscpy (workprefs.cdimagefile[0], quickstart_cddrive);
                                } else {
                                        eject_cd ();
                                        quickstart_cdtype = val;
                                        if (val > 0)
-                                               workprefs.cdimagefileuse = true;
+                                               workprefs.cdimagefileuse[0] = true;
 
                                }
                                addcdtype (hDlg, IDC_CD_TYPE);
@@ -9401,7 +9401,7 @@ static void addfloppyhistory_2 (HWND hDlg, int n, int f_text, int type)
        SendDlgItemMessage (hDlg, f_text, CB_RESETCONTENT, 0, 0);
        if (type == HISTORY_CD) {
                nn = 1;
-               text = workprefs.cdimagefile;
+               text = workprefs.cdimagefile[0];
        } else {
                nn = workprefs.dfxtype[n] + 1;
                text = workprefs.df[n];
@@ -9483,7 +9483,7 @@ static void addcdtype (HWND hDlg, int id)
        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])
+               if (full_property_sheet && !workprefs.cdimagefileuse[0] && !workprefs.cdimagefile[0][0])
                        cdtype = 0;
        }
        int cnt = 2;
@@ -9495,7 +9495,7 @@ static void addcdtype (HWND hDlg, int id)
                        SendDlgItemMessage (hDlg, id, CB_ADDSTRING, 0, (LPARAM)vol);
                        if (!_tcsicmp (vol, quickstart_cddrive)) {
                                cdtype = quickstart_cdtype = cnt;
-                               _tcscpy (workprefs.cdimagefile, vol);
+                               _tcscpy (workprefs.cdimagefile[0], vol);
                        }
                        cnt++;
                }
@@ -9541,7 +9541,7 @@ static void addfloppytype (HWND hDlg, int n)
                        SetWindowText (GetDlgItem (hDlg, f_enable), tmp);
                        addcdtype (hDlg, IDC_CD0Q_TYPE);
                        hide (hDlg, IDC_CD0Q_TYPE, 0);
-                       text = workprefs.cdimagefile;
+                       text = workprefs.cdimagefile[0];
                        regsetstr (NULL, L"QuickStartCDDrive", quickstart_cdtype >= 2 ? quickstart_cddrive : L"");
                        regsetint (NULL, L"QuickStartCDType", quickstart_cdtype >= 2 ? 2 : quickstart_cdtype);
                } else {
@@ -9671,7 +9671,7 @@ static void getfloppyname (HWND hDlg, int n, int cd, int f_text)
                } else {
                        if (quickstart_cddrive[0])
                                eject_cd ();
-                       _tcscpy (workprefs.cdimagefile, tmp);
+                       _tcscpy (workprefs.cdimagefile[0], tmp);
                }
        }
 }
@@ -13623,7 +13623,7 @@ int dragdrop (HWND hDlg, HDROP hd, struct uae_prefs *prefs, int currentpage)
                        ret = 1;
                        break;
                case ZFILE_CDIMAGE:
-                       _tcscpy (workprefs.cdimagefile, file);
+                       _tcscpy (workprefs.cdimagefile[0], file);
                        break;
                default:
                        if (currentpage < 0 && !full_property_sheet) {
index d079ec5d9a811238ec653608266482624a13febe..25b9d13915cef7ef59e052bcd90534452c394d73 100644 (file)
@@ -1,4 +1,52 @@
 
+Beta 4:
+
+- rawinput was disabled if only one keyboard device was detected, input didn't work at all
+  in b3 because of null keyboard (detected only one rawinput keyboard = it was ignore but null
+  keyboard was still added later -> more than one keyboard -> do not fallback to directinput..)
+- redirect unknown rawinput messages to null keyboard (shouldn't happen but you never know..)
+- spaces not allowed in directory filesystem volume name (wrong validation routine used)
+- bottom border was half-blanked in some doublescanned modes
+
+Another major CD update. CD configuration unified, now any CD unit "slot" can point to different
+CD backend (image mounter + scsi emulation, IOCTL drive + scsi emulation, SPTI drive + scsi
+passthrough) On the fly changes fully supported. CD mess is nearly gone, code is finally structured
+logically without special cases. (this finally made SCSI emulation quite easy to implement)
+
+- SCSI emulation is now the default SCSI mode (CDFS and audio tracks always work, switch to
+  SPTI if you need advanced stuff like cd writing) Some audio CD players work for the first time
+  now because some SCSI commands have been obsoleted long time ago like PLAY TRACK/INDEX
+- CD audio DAE emulation does not attempt to play data tracks anymore
+- added most common CD audio SCSI commands to SCSI emulator, OS3.5+ PlayCD confirmed working.
+  Following new SCSI command added:
+  START/STOP, STOP PLAY/SCAN, SCAN, PLAY AUDIO MSF, PLAY AUDIO, PLAY CD, PLAY TRACK/INDEX,
+  PAUSE/RESUME, READ SUB-CHANNEL, READ TOC, MODE SENSE/MODE SELECT (cd audio volume page only),
+  READ CD and READ CF MSF (only audio extraction supported + subchannel options)
+- added CD audio io commands to uaescsi.device (most programs use HD_SCSICMD)
+- emulated INQUIRY vendor, product and revision fetched from real device if possible
+
+Testing:
+
+Load your normal WB3.x configuration (that uses uaescsi.device CDROMs), start emulation
+normally. (This and following betas force SCSI Emulation mode!) Report all changes,
+including logs, SCSI emulation logging is enabled.
+
+Notes:
+
+GUI selection overrides slot 0, for example if you normally have D:\ = uaescsi.device unit 0
+and E:\ = uaescsi.device unit 1, mounting a cd image "ejects" whatever is in unit 0 and
+replaces it with image file.
+
+If CD32 or CDTV is started in "autodetect" mode and it chose unit 1 or later (CD32/CDTV or
+Audio CD inserted), unit 0 changes are ignored until original drive becomes empty. This
+needs to be more intelligent.
+
+Configuration file accepts cdimage0 to cdimage7. Full syntax:
+cdimagex=image path or device name,cd backend(:reserved for future)
+Cd backend not mandatory. Supported CD backend names are:
+image, ioctl, spti and aspi. (this is autoselected when using GUI)
+
+Beta 3:
 
 - 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
index d0d6804e1e5c1da21445dfe759184c9843195cd2..366fbbe9ae720582653f01a6af0f98e4291707f2 100644 (file)
--- a/scsi.cpp
+++ b/scsi.cpp
@@ -98,7 +98,7 @@ struct scsi_data *scsi_alloc(int id, struct hd_hardfiledata *hfd)
 struct scsi_data *scsi_alloc_native(int id, int nativeunit)
 {
        struct scsi_data *sd;
-       if (!sys_command_open (DF_SCSI, nativeunit)) {
+       if (!sys_command_open (nativeunit)) {
                write_log (L"SCSI: native scsi unit %d failed to open\n", nativeunit);
                return NULL;
        }
@@ -118,7 +118,7 @@ void scsi_free(struct scsi_data *sd)
        if (!sd)
                return;
        if (sd->nativescsiunit >= 0) {
-               sys_command_close (DF_SCSI, sd->nativescsiunit);
+               sys_command_close (sd->nativescsiunit);
        }
        xfree(sd);
 }
index 188463cd62a13c2d7d9ab94a10935fa143156e36..9938a0a5687fa557e7f07f37214076d154c82c47 100644 (file)
 #define ASYNC_REQUEST_NONE 0
 #define ASYNC_REQUEST_TEMP 1
 #define ASYNC_REQUEST_CHANGEINT 10
+#define ASYNC_REQUEST_FRAMEINT 11
 
 struct devstruct {
        int unitnum, aunit;
        int opencnt;
        int changenum;
-       int allow_scsi;
-       int allow_ioctl;
        int drivetype;
        int iscd;
        volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
@@ -55,6 +54,13 @@ struct devstruct {
        volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
        struct device_info di;
        uaecptr changeint;
+       int changeint_mediastate;
+
+       int configblocksize;
+       int volumelevel;
+       int fadeframes;
+       int fadetarget;
+       int fadecounter;
 
        smp_comm_pipe requests;
        int thread_running;
@@ -65,21 +71,23 @@ struct priv_devstruct {
        int inuse;
        int unit;
        int mode;
-       int scsi;
-       int ioctl;
-       int noscsi;
        int type;
        int flags; /* OpenDevice() */
 };
 
-static struct devstruct devst[MAX_TOTAL_DEVICES];
+static struct devstruct devst[MAX_TOTAL_SCSI_DEVICES];
 static struct priv_devstruct pdevst[MAX_OPEN_DEVICES];
 static uae_u32 nscmd_cmd;
 static uae_sem_t change_sem;
 
-static struct device_info *devinfo (int mode, int unitnum, struct device_info *di)
+static struct device_info *devinfo (struct devstruct *devst, struct device_info *di)
 {
-       return sys_command_info (mode, unitnum, di, 0);
+       struct device_info *dio = sys_command_info (devst->unitnum, di, 0);
+       if (dio) {
+               if (!devst->configblocksize)
+                       devst->configblocksize = dio->bytespersector;
+       }       
+       return dio;
 }
 
 static void io_log (const TCHAR *msg, uaecptr request)
@@ -94,8 +102,9 @@ static void io_log (const TCHAR *msg, uaecptr request)
 static struct devstruct *getdevstruct (int unit)
 {
        int i;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
-               if (unit >= 0 && devst[i].aunit == unit) return &devst[i];
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
+               if (unit >= 0 && devst[i].aunit == unit)
+                       return &devst[i];
        }
        return 0;
 }
@@ -139,10 +148,7 @@ static void dev_close_3 (struct devstruct *dev, struct priv_devstruct *pdev)
        if (!dev->opencnt) return;
        dev->opencnt--;
        if (!dev->opencnt) {
-               if (pdev->scsi)
-                       sys_command_close (DF_SCSI, dev->unitnum);
-               if (pdev->ioctl)
-                       sys_command_close (DF_IOCTL, dev->unitnum);
+               sys_command_close (dev->unitnum);
                pdev->inuse = 0;
                write_comm_pipe_u32 (&dev->requests, 0, 1);
        }
@@ -183,13 +189,6 @@ static int openfail (uaecptr ioreq, int error)
        return (uae_u32)-1;
 }
 
-static void setpdev (struct priv_devstruct *pdev, struct devstruct *dev)
-{
-       pdev->scsi = dev->allow_scsi ? 1 : 0;
-       pdev->ioctl = dev->allow_scsi ? 0 : 1;
-       pdev->mode = dev->allow_scsi ? DF_SCSI : DF_IOCTL;
-}
-
 static uae_u32 REGPARAM2 dev_open_2 (TrapContext *context, int type)
 {
        uaecptr ioreq = m68k_areg (regs, 1);
@@ -201,23 +200,17 @@ static uae_u32 REGPARAM2 dev_open_2 (TrapContext *context, int type)
 
        if (log_scsi)
                write_log (L"opening %s:%d ioreq=%08X\n", getdevname (type), unit, ioreq);
-       if (get_word (ioreq + 0x12) < IOSTDREQ_SIZE)
+       if (get_word (ioreq + 0x12) < IOSTDREQ_SIZE && get_word (ioreq + 0x12) > 0)
                return openfail (ioreq, IOERR_BADLENGTH);
        if (!dev)
                return openfail (ioreq, 32); /* badunitnum */
        if (!dev->opencnt) {
                for (i = 0; i < MAX_OPEN_DEVICES; i++) {
                        pdev = &pdevst[i];
-                       if (pdev->inuse == 0) break;
-               }
-               if (type == UAEDEV_SCSI_ID && sys_command_open (dev->allow_scsi ? DF_SCSI : DF_IOCTL, dev->unitnum)) {
-                       setpdev (pdev, dev);
-               }
-               if (type == UAEDEV_DISK_ID && sys_command_open (DF_IOCTL, dev->unitnum)) {
-                       pdev->ioctl = 1;
-                       pdev->mode = DF_IOCTL;
+                       if (pdev->inuse == 0)
+                               break;
                }
-               if (!pdev->scsi && !pdev->ioctl)
+               if (!sys_command_open (dev->unitnum))
                        return openfail (ioreq, IOERR_OPENFAIL);
                pdev->type = type;
                pdev->unit = unit;
@@ -270,53 +263,39 @@ static int is_async_request (struct devstruct *dev, uaecptr request)
        return 0;
 }
 
-
+#if 0
 static int scsiemul_switchscsi (const TCHAR *name)
 {
        struct devstruct *dev = NULL;
        struct device_info *discsi, discsi2;
-       int i, j, opened[MAX_TOTAL_DEVICES];
+       int i, opened[MAX_TOTAL_SCSI_DEVICES];
        bool wasopen = false;
 
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++)
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
                opened[i] = sys_command_isopen (i);
 
        dev = &devst[0];
-       if ((dev->allow_ioctl || dev->allow_scsi) && dev->opencnt)
+       if (dev->opencnt)
                wasopen = true;
-       if (dev->allow_scsi)
-               sys_command_close (DF_SCSI, dev->unitnum);
-       if (dev->allow_ioctl)
-               sys_command_close (DF_IOCTL, dev->unitnum);
-       dev->allow_ioctl = 0;
-       dev->allow_scsi = 0;
+       sys_command_close (dev->unitnum);
 
        dev = NULL;
-       for (j = 0; j < 2; j++) {
-               int mode = j == 0 ? DF_SCSI : DF_IOCTL;
-               if (!(device_func_init (j == 0 ? DEVICE_TYPE_SCSI : DEVICE_TYPE_ANY) & (1 << mode)))
-                       continue;
+       if (device_func_init (DEVICE_TYPE_ANY)) {
                if (devst[0].di.media_inserted < 0)
                        devst[0].di.media_inserted = 0;
                i = 0;
-               while (i < MAX_TOTAL_DEVICES && dev == NULL) {
+               while (i < MAX_TOTAL_SCSI_DEVICES && dev == NULL) {
                        discsi = 0;
-                       if (sys_command_open (mode, i)) {
-                               discsi = sys_command_info (mode, i, &discsi2, 0);
+                       if (sys_command_open ( i)) {
+                               discsi = sys_command_info (i, &discsi2, 0);
                                if (discsi && discsi->type == INQ_ROMD) {
-                                       if (!_tcsicmp (currprefs.cdimagefile, discsi->label)) {
+                                       if (!_tcsicmp (currprefs.cdimagefile[0], discsi->label)) {
                                                dev = &devst[0];
                                                dev->unitnum = i;
-                                               dev->allow_scsi = j == 0 ? 1 : 0;
-                                               dev->allow_ioctl = j != 0 ? 1 : 0;
                                                dev->drivetype = discsi->type;
                                                memcpy (&dev->di, discsi, sizeof (struct device_info));
                                                dev->iscd = 1;
-                                               write_log (L"%s mounted as uaescsi.device:0 (SCSI=%d IOCTL=%d)\n", discsi->label, dev->allow_scsi, dev->allow_ioctl);
-                                               if (dev->aunit >= 0) {
-                                                       struct priv_devstruct *pdev = &pdevst[dev->aunit];
-                                                       setpdev (pdev, dev);
-                                               }
+                                               write_log (L"%s mounted as uaescsi.device:0\n", discsi->label);
                                                if (dev->di.media_inserted) {
                                                        dev->di.media_inserted = 0;
                                                        scsi_do_disk_change (dev->di.id, 1, NULL);
@@ -324,7 +303,7 @@ static int scsiemul_switchscsi (const TCHAR *name)
                                        }
                                }
                                if (opened[i] == 0 && !wasopen)
-                                       sys_command_close (mode, i);
+                                       sys_command_close ( i);
                        }
                        i++;
                }
@@ -333,49 +312,10 @@ static int scsiemul_switchscsi (const TCHAR *name)
        }
        return -1;
 }
-static int scsiemul_switchemu (const TCHAR *name)
-{
-       struct devstruct *dev = NULL;
-       struct device_info *discsi, discsi2;
-
-       if (!device_func_init (DEVICE_TYPE_ANY | DEVICE_TYPE_ALLOWEMU))
-               return -1;
-       int opened = sys_command_isopen (0);
-       if (sys_command_open (DF_IOCTL, 0)) {
-               if (discsi = sys_command_info (DF_IOCTL, 0, &discsi2, 0)) {
-                       dev = &devst[0];
-                       dev->unitnum = 0;
-                       dev->allow_scsi = 1;
-                       dev->allow_ioctl = 1;
-                       dev->drivetype = discsi->type;
-                       memcpy (&dev->di, discsi, sizeof (struct device_info));
-                       dev->iscd = 1;
-                       write_log (L"IMG_EMU (%s) mounted as uaescsi.device:0\n", name);
-                       if (dev->aunit >= 0) {
-                               struct priv_devstruct *pdev = &pdevst[dev->aunit];
-                               setpdev (pdev, dev);
-                       }
-                       dev->di.media_inserted = 0;
-               }
-               if (!opened)
-                       sys_command_close (DF_IOCTL, 0);
-               return 0;
-       }
-       return -1;
-}
-
-int scsi_do_disk_device_change (void)
-{
-       int ret = scsiemul_switchscsi (currprefs.cdimagefile);
-       if (ret < 0) {
-               scsiemul_switchemu (currprefs.cdimagefile);
-       }
-       return ret;
-}
+#endif
 
-// device_id = -1 and insert==0 -> all medias going away
 // 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 scsi_do_disk_change (int unitnum, int insert, int *pollmode)
 {
        int i, j, ret;
 
@@ -383,19 +323,18 @@ int scsi_do_disk_change (int device_id, int insert, int *pollmode)
        if (!change_sem)
                return ret;
        uae_sem_wait (&change_sem);
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                struct devstruct *dev = &devst[i];
-               if (dev->di.id == device_id || (device_id < 0 && i == 0)) {
+               if (dev->di.unitnum == unitnum + 1) {
                        ret = i;
-                       if ((dev->di.media_inserted > 0 && insert == 0) || (dev->di.media_inserted <= 0 && insert)) {
+                       if ((dev->changeint_mediastate > 0 && insert == 0) || (dev->changeint_mediastate <= 0 && insert)) {
+                               dev->changeint_mediastate = insert;
                                if (pollmode)
                                        *pollmode = 1;
                                if (dev->aunit >= 0) {
                                        struct priv_devstruct *pdev = &pdevst[dev->aunit];
-                                       devinfo (pdev->mode, dev->unitnum, &dev->di);
+                                       devinfo (dev, &dev->di);
                                }
-                               if (device_id < 0 && insert == 0)
-                                       dev->di.media_inserted = -1; // stay away!
                                dev->changenum++;
                                j = 0;
                                while (j < MAX_ASYNC_REQUESTS) {
@@ -483,18 +422,17 @@ static void abort_async (struct devstruct *dev, uaecptr request, int errcode, in
                write_log (L"asyncronous request=%08X aborted, error=%d\n", request, errcode);
 }
 
-static int command_read (int mode, struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
+static int command_read (struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
 {
        int blocksize = dev->di.bytespersector;
-       uae_u8 *temp;
 
        length /= blocksize;
        offset /= blocksize;
        while (length > 0) {
-               temp = sys_command_read (mode, dev->unitnum, NULL, offset, 1);
-               if (!temp)
+               uae_u8 buffer[4096];
+               if (!sys_command_read (dev->unitnum, buffer, offset, 1))
                        return 20;
-               memcpyha_safe (data, temp, blocksize);
+               memcpyha_safe (data, buffer, blocksize);
                data += blocksize;
                offset++;
                length--;
@@ -502,19 +440,16 @@ static int command_read (int mode, struct devstruct *dev, uaecptr data, uae_u64
        return 0;
 }
 
-static int command_write (int mode, struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
+static int command_write (struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
 {
        uae_u32 blocksize = dev->di.bytespersector;
-       struct device_scsi_info dsi;
-
-       if (!sys_command_scsi_info (mode, dev->unitnum, &dsi))
-               return 20;
        length /= blocksize;
        offset /= blocksize;
        while (length > 0) {
+               uae_u8 buffer[4096];
                int err;
-               memcpyah_safe (dsi.buffer, data, blocksize);
-               err = sys_command_write (mode, dev->unitnum, NULL, offset, 1);
+               memcpyah_safe (buffer, data, blocksize);
+               err = sys_command_write (dev->unitnum, buffer, offset, 1);
                if (!err)
                        return 20;
                if (err < 0)
@@ -526,31 +461,35 @@ static int command_write (int mode, struct devstruct *dev, uaecptr data, uae_u64
        return 0;
 }
 
-static int command_cd_read (int mode, struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
+static int command_cd_read (struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
 {
-       uae_u8 *temp;
        uae_u32 len, sector, startoffset;
+       int blocksize;
 
+       blocksize = dev->configblocksize;
        *io_actual = 0;
-       if (dev->di.bytespersector == 0)
-               dev->di.bytespersector = 2048;
-       startoffset = offset % dev->di.bytespersector;
+       startoffset = offset % blocksize;
        offset -= startoffset;
-       sector = offset / dev->di.bytespersector;
+       sector = offset / blocksize;
        while (length > 0) {
-               temp = sys_command_cd_read (mode, dev->unitnum, NULL, sector, 1);
-               if (!temp)
-                       return 20;
+               uae_u8 temp[4096];
+               if (blocksize != 2048) {
+                       if (!sys_command_cd_rawread (dev->unitnum, temp, sector, 1, blocksize))
+                               return 20;
+               } else {
+                       if (!sys_command_cd_read (dev->unitnum, temp, sector, 1))
+                               return 20;
+               }
                if (startoffset > 0) {
-                       len = dev->di.bytespersector - startoffset;
+                       len = blocksize - startoffset;
                        if (len > length) len = length;
                        memcpyha_safe (data, temp + startoffset, len);
                        length -= len;
                        data += len;
                        startoffset = 0;
                        *io_actual += len;
-               } else if (length >= dev->di.bytespersector) {
-                       len = dev->di.bytespersector;
+               } else if (length >= blocksize) {
+                       len = blocksize;
                        memcpyha_safe (data, temp, len);
                        length -= len;
                        data += len;
@@ -582,6 +521,9 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                return 0;
        command = get_word (request + 28);
 
+//     write_log (L"%d: CMD=%04X DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n",
+//             command, io_data, io_length, io_offset, io_actual);
+
        switch (command)
        {
        case CMD_READ:
@@ -589,13 +531,13 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                if (dev->di.media_inserted <= 0)
                        goto no_media;
                if (dev->drivetype == INQ_ROMD) {
-                       io_error = command_cd_read (pdev->mode, dev, io_data, io_offset, io_length, &io_actual);
+                       io_error = command_cd_read (dev, io_data, io_offset, io_length, &io_actual);
                } else {
                        if ((io_offset & bmask) || bmask == 0 || io_data == 0)
                                goto bad_command;
                        if ((io_length & bmask) || io_length == 0)
                                goto bad_len;
-                       io_error = command_read (pdev->mode, dev, io_data, io_offset, io_length, &io_actual);
+                       io_error = command_read (dev, io_data, io_offset, io_length, &io_actual);
                }
                break;
        case TD_READ64:
@@ -608,9 +550,9 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                if ((io_length & bmask) || io_length == 0)
                        goto bad_len;
                if (dev->drivetype == INQ_ROMD)
-                       io_error = command_cd_read (pdev->mode, dev, io_data, io_offset64, io_length, &io_actual);
+                       io_error = command_cd_read (dev, io_data, io_offset64, io_length, &io_actual);
                else
-                       io_error = command_read (pdev->mode, dev, io_data, io_offset64, io_length, &io_actual);
+                       io_error = command_read (dev, io_data, io_offset64, io_length, &io_actual);
                break;
 
        case CMD_WRITE:
@@ -623,7 +565,7 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                } else if ((io_length & bmask) || io_length == 0) {
                        goto bad_len;
                } else {
-                       io_error = command_write (pdev->mode, dev, io_data, io_offset, io_length, &io_actual);
+                       io_error = command_write (dev, io_data, io_offset, io_length, &io_actual);
                }
                break;
        case TD_WRITE64:
@@ -638,7 +580,7 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                } else if ((io_length & bmask) || io_length == 0) {
                        goto bad_len;
                } else {
-                       io_error = command_write (pdev->mode, dev, io_data, io_offset64, io_length, &io_actual);
+                       io_error = command_write (dev, io_data, io_offset64, io_length, &io_actual);
                }
                break;
 
@@ -652,7 +594,7 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                } else if ((io_length & bmask) || io_length == 0) {
                        goto bad_len;
                } else {
-                       io_error = command_write (pdev->mode, dev, io_data, io_offset, io_length, &io_actual);
+                       io_error = command_write (dev, io_data, io_offset, io_length, &io_actual);
                }
                break;
        case TD_FORMAT64:
@@ -667,7 +609,7 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                } else if ((io_length & bmask) || io_length == 0) {
                        goto bad_len;
                } else {
-                       io_error = command_write (pdev->mode, dev, io_data, io_offset64, io_length, &io_actual);
+                       io_error = command_write (dev, io_data, io_offset64, io_length, &io_actual);
                }
                break;
 
@@ -681,19 +623,20 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
        case CMD_REMOVE:
                io_actual = dev->changeint;
                dev->changeint = io_data;
+               dev->changeint_mediastate = dev->di.media_inserted;
                break;
        case CMD_CHANGENUM:
                io_actual = dev->changenum;
                break;
        case CMD_CHANGESTATE:
                if (dev->di.media_inserted >= 0) {
-                       io_actual = devinfo (pdev->mode, dev->unitnum, &dev->di)->media_inserted > 0 ? 0 : 1;
+                       io_actual = devinfo (dev, &dev->di)->media_inserted > 0 ? 0 : 1;
                } else {
                        io_actual = 1;
                }
                break;
        case CMD_PROTSTATUS:
-               io_actual = devinfo (pdev->mode, dev->unitnum, &dev->di)->write_protected ? -1 : 0;
+               io_actual = devinfo (dev, &dev->di)->write_protected ? -1 : 0;
                break;
        case CMD_GETDRIVETYPE:
                io_actual = dev->drivetype;
@@ -706,7 +649,7 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
        case CMD_GETGEOMETRY:
                {
                        struct device_info *di;
-                       di = devinfo (pdev->mode, dev->unitnum, &dev->di);
+                       di = devinfo (dev, &dev->di);
                        if (di->media_inserted <= 0)
                                goto no_media;
                        put_long (io_data + 0, di->bytespersector);
@@ -722,6 +665,7 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
                }
                break;
        case CMD_ADDCHANGEINT:
+               dev->changeint_mediastate = dev->di.media_inserted;
                io_error = add_async_request (dev, request, ASYNC_REQUEST_CHANGEINT, io_data);
                if (!io_error)
                        async = 1;
@@ -729,14 +673,193 @@ static int dev_do_io (struct devstruct *dev, uaecptr request)
        case CMD_REMCHANGEINT:
                release_async_request (dev, request);
                break;
+
+       case CD_TOCLSN:
+       case CD_TOCMSF:
+       {
+               int msf = command == CD_TOCMSF;
+               struct cd_toc_head toc;
+               if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
+                       if (io_offset == 0 && io_length > 0) {
+                               int pos = toc.lastaddress;
+                               put_byte (io_data, toc.first_track);
+                               put_byte (io_data + 1, toc.last_track);
+                               if (msf)
+                                       pos = lsn2msf (pos);
+                               put_long (io_data + 2, pos);
+                               io_offset++;
+                               io_length--;
+                               io_data += 6;
+                               io_actual++;
+                       }
+                       for (int i = toc.first_track_offset; i < toc.last_track_offset && io_length > 0; i++) {
+                               if (io_offset == toc.toc[i].point) {
+                                       int pos = toc.toc[i].paddress;
+                                       put_byte (io_data, (toc.toc[i].control << 4) | toc.toc[i].adr);
+                                       put_byte (io_data + 1, toc.toc[i].point);
+                                       if (msf)
+                                               pos = lsn2msf (pos);
+                                       put_long (io_data + 2, pos);
+                                       io_offset++;
+                                       io_length--;
+                                       io_data += 6;
+                                       io_actual++;
+                               }
+                       }
+               } else {
+                       io_error = CDERR_NotSpecified;
+               }
+       }
+       break;
+       case CD_ADDFRAMEINT:
+               io_error = add_async_request (dev, request, ASYNC_REQUEST_FRAMEINT, io_data);
+               if (!io_error)
+                       async = 1;
+               break;
+       case CD_REMFRAMEINT:
+               release_async_request (dev, request);
+               break;
+       case CD_ATTENUATE:
+       {
+               if (io_offset != -1) {
+                       dev->fadeframes = io_length & 0x7fff;
+                       dev->fadetarget = io_offset & 0x7fff;
+               }
+               io_actual = dev->volumelevel;
+       }
+       break;
+       case CD_INFO:
+       {
+               uae_u16 status = 0;
+               struct cd_toc_head toc;
+               uae_u8 subq[SUBQ_SIZE] = { 0 };
+               sys_command_cd_qcode (dev->di.unitnum, subq);
+               status |= 1 << 0; // door closed
+               if (dev->di.media_inserted) {
+                       status |= 1 << 1;
+                       status |= 1 << 2; // motor on
+                       if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
+                               status |= 1 << 3; // toc
+                               if (subq[1] == AUDIO_STATUS_IN_PROGRESS || subq[1] == AUDIO_STATUS_PAUSED)
+                                       status |= 1 << 5; // audio play
+                               if (subq[1] == AUDIO_STATUS_PAUSED)
+                                       status |= 1 << 6; // paused
+                               if (isdatatrack (&toc, 0))
+                                       status |= 1 << 4; // data track
+                       }
+               }
+               put_word (io_data +  0, 75);            // PlaySpeed
+               put_word (io_data +  2, 1200);          // ReadSpeed (randomly chose 16x)
+               put_word (io_data +  4, 1200);          // ReadXLSpeed
+               put_word (io_data +  6, dev->configblocksize); // SectorSize
+               put_word (io_data +  8, -1);            // XLECC
+               put_word (io_data + 10, 0);                     // EjectReset
+               put_word (io_data + 12, 0);                     // Reserved * 4
+               put_word (io_data + 14, 0);
+               put_word (io_data + 16, 0);
+               put_word (io_data + 18, 0);
+               put_word (io_data + 20, 1200);          // MaxSpeed
+               put_word (io_data + 22, 0xffff);        // AudioPrecision (volume)
+               put_word (io_data + 24, status);        // Status
+               put_word (io_data + 26, 0);                     // Reserved2 * 4
+               put_word (io_data + 28, 0);
+               put_word (io_data + 30, 0);
+               put_word (io_data + 32, 0);
+               io_actual = 34;
+       }
+       break;
+       case CD_CONFIG:
+       {
+               while (get_long (io_data) != TAG_DONE) {
+                       uae_u32 tag = get_long (io_data);
+                       uae_u32 data = get_long (io_data + 4);
+                       if (tag == 4) {
+                               // TAGCD_SECTORSIZE
+                               if (data == 2048 || data == 2336 || data == 2352)
+                                       dev->configblocksize = data;
+                               else
+                                       io_error = IOERR_BADADDRESS;
+
+                       }
+                       io_data += 8;
+               }
+               break;
+       }
+       case CD_PAUSE:
+       {
+               int old = sys_command_cd_pause (dev->di.unitnum, io_length);
+               if (old >= 0)
+                       io_actual = old;
+               else
+                       io_error = IOERR_BADADDRESS;
+               break;
+       }
+       case CD_PLAYLSN:
+       {
+               int start = io_offset;
+               int end = io_length + start;
+               if (!sys_command_cd_play (dev->di.unitnum, start, end, 0, NULL))
+                       io_error = IOERR_BADADDRESS;
+       }
+       break;
+       case CD_PLAYMSF:
+       {
+               int start = msf2lsn (io_offset);
+               int end = msf2lsn (io_length) + start;
+               if (!sys_command_cd_play (dev->di.unitnum, start, end, 0, NULL))
+                       io_error = IOERR_BADADDRESS;
+       }
+       break;
+       case CD_PLAYTRACK:
+       {
+               struct cd_toc_head toc;
+               int ok = 0;
+               if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
+                       for (int i = toc.first_track_offset; i < toc.last_track_offset; i++) {
+                               if (i == io_offset && i + io_length <= toc.last_track_offset) {
+                                       ok = sys_command_cd_play (dev->di.unitnum, toc.toc[i].address, toc.toc[i + io_length].address, 0, NULL);
+                                       break;
+                               }
+                       }
+               }
+               if (!ok)
+                       io_error = IOERR_BADADDRESS;
+       }
+       break;
+       case CD_QCODEMSF:
+       case CD_QCODELSN:
+       {
+               uae_u8 subq[SUBQ_SIZE];
+               if (sys_command_cd_qcode (dev->di.unitnum, subq)) {
+                       if (subq[1] == AUDIO_STATUS_IN_PROGRESS || subq[1] == AUDIO_STATUS_PAUSED) {
+                               put_byte (io_data + 0, subq[4 + 0]);
+                               put_byte (io_data + 1, frombcd (subq[4 + 1]));
+                               put_byte (io_data + 2, frombcd (subq[4 + 2]));
+                               put_byte (io_data + 3, subq[4 + 6]);
+                               int trackpos = fromlongbcd (subq + 4 + 3);
+                               int diskpos = fromlongbcd (subq + 4 + 7);
+                               if (command == CD_QCODELSN) {
+                                       trackpos = msf2lsn (trackpos);
+                                       diskpos = msf2lsn (diskpos);
+                               }
+                               put_long (io_data + 4, trackpos);
+                               put_long (io_data + 8, diskpos);
+                               io_actual = 12;
+                       } else {
+                               io_error = CDERR_InvalidState;
+                       }
+               } else {
+                       io_error = IOERR_BADADDRESS;
+               }
+       }
+       break;
+
        case HD_SCSICMD:
-               if (dev->allow_scsi && pdev->scsi) {
+               {
                        uae_u32 sdd = get_long (request + 40);
                        io_error = sys_command_scsi_direct (dev->unitnum, sdd);
                        if (log_scsi)
                                write_log (L"scsidev: did io: sdd %p request %p error %d\n", sdd, request, get_byte (request + 31));
-               } else {
-                       io_error = IOERR_NOCMD;
                }
                break;
        case NSCMD_DEVICEQUERY:
@@ -892,10 +1015,9 @@ static void dev_reset (void)
 {
        int i, j;
        struct devstruct *dev;
-       struct device_info *discsi, discsi2;
        int unitnum = 0;
 
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                dev = &devst[i];
                if (dev->opencnt > 0) {
                        for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
@@ -904,10 +1026,7 @@ static void dev_reset (void)
                                        abort_async (dev, request, 0, 0);
                        }
                        dev->opencnt = 1;
-                       if (dev->allow_scsi)
-                               sys_command_close (DF_SCSI, dev->unitnum);
-                       if (dev->allow_ioctl)
-                               sys_command_close (DF_IOCTL, dev->unitnum);
+                       sys_command_close (dev->unitnum);
                }
                memset (dev, 0, sizeof (struct devstruct));
                dev->unitnum = dev->aunit = -1;
@@ -915,52 +1034,39 @@ static void dev_reset (void)
        for (i = 0; i < MAX_OPEN_DEVICES; i++)
                memset (&pdevst[i], 0, sizeof (struct priv_devstruct));
 
-       int didswitch = -1;
-       if (currprefs.cdimagefile[0] || currprefs.cdimagefileuse)
-               didswitch = scsiemul_switchscsi (currprefs.cdimagefile);
-       if (didswitch < 0) {
-               device_func_init (DEVICE_TYPE_SCSI);
-               i = j = 0;
-               while (i < MAX_TOTAL_DEVICES) {
-                       int mode = -1;
-                       dev = &devst[i];
-                       discsi = 0;
-                       if (sys_command_open (DF_SCSI, j)) {
-                               dev->allow_scsi = 1;
-                               mode = DF_SCSI;
-                       }
-                       if (!dev->allow_scsi) {
-                               if (sys_command_open (DF_IOCTL, j)) {
-                                       dev->allow_ioctl = 1;
-                                       mode = DF_IOCTL;
-                               }
-                       }
-                       if (mode >= 0) {
-                               discsi = sys_command_info (mode, j, &discsi2, 0);
-                               sys_command_close (mode, j);
-                       }
+       device_func_init (0);
+       i = 0;
+       while (i < MAX_TOTAL_SCSI_DEVICES) {
+               dev = &devst[i];
+               struct device_info *discsi, discsi2;
+               if (sys_command_open (i)) {
+                       discsi = sys_command_info (i, &discsi2, 0);
                        if (discsi) {
-                               dev->unitnum = j;
+                               dev->unitnum = i;
                                dev->drivetype = discsi->type;
                                memcpy (&dev->di, discsi, sizeof (struct device_info));
+                               dev->changeint_mediastate = discsi->media_inserted;
+                               dev->configblocksize = discsi->bytespersector;
                                if (discsi->type == INQ_ROMD)
                                        dev->iscd = 1;
                        }
-                       i++;
-                       j++;
                }
+               i++;
        }
        unitnum = 0;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                dev = &devst[i];
+               if (dev->unitnum >= 0)
+                       sys_command_close (dev->unitnum);
                if (dev->unitnum >= 0 && dev->iscd) {
                        dev->aunit = unitnum;
+                       dev->volumelevel = 0x7fff;
                        unitnum++;
                }
        }
        if (unitnum == 0)
                unitnum = 1;
-       for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
                dev = &devst[i];
                if (dev->unitnum >= 0) {
                        if (!dev->iscd) {
index 6a45aac6c667b4ccaabd1aeb0bce8bc924190e71..0d9c333635d6797596a6aeefb6c9d6bf09293d2d 100644 (file)
@@ -196,6 +196,8 @@ struct zfile *archive_access_select (struct znode *parent, struct zfile *zf, uns
                                        if ((mask & ZFD_CD) && ft) {
                                                if (ext && !_tcsicmp (ext, L".iso"))
                                                        whf = 2;
+                                               if (ext && !_tcsicmp (ext, L".ccd"))
+                                                       whf = 9;
                                                if (ext && !_tcsicmp (ext, L".cue"))
                                                        whf = 10;
                                        }