diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 4ccb81442..2cdcc5a22 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2641,18 +2641,6 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) return ret; } -int -cdrom_ext_medium_changed(const cdrom_t *dev) -{ - int ret = 0; - - if (dev && dev->ops && dev->ops->ext_medium_changed && - (dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED)) - ret = dev->ops->ext_medium_changed(dev->local); - - return ret; -} - int cdrom_is_empty(const uint8_t id) { @@ -2700,6 +2688,44 @@ cdrom_toc_dump(cdrom_t *dev) } #endif +void +cdrom_set_empty(cdrom_t *dev) +{ + dev->cd_status = CD_STATUS_EMPTY; +} + +void +cdrom_update_status(cdrom_t *dev) +{ + const int was_empty = (dev->cd_status == CD_STATUS_EMPTY); + + if (dev->ops->load != NULL) + dev->ops->load(dev->local); + + /* All good, reset state. */ + dev->seek_pos = 0; + dev->cd_buflen = 0; + + if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) + dev->cd_status = CD_STATUS_EMPTY; + else if (dev->ops->is_dvd(dev->local)) + dev->cd_status = CD_STATUS_DVD; + else + dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : + CD_STATUS_DATA_ONLY; + + dev->cdrom_capacity = dev->ops->get_last_block(dev->local); + + if (dev->cd_status != CD_STATUS_EMPTY) { + /* Signal media change to the emulated machine. */ + cdrom_insert(dev->id); + + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + cdrom_insert(dev->id); + } +} + int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) { @@ -2728,10 +2754,12 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) dev->seek_pos = 0; dev->cd_buflen = 0; + if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) + dev->cd_status = CD_STATUS_EMPTY; if (dev->ops->is_dvd(dev->local)) dev->cd_status = CD_STATUS_DVD; else - dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : + dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : CD_STATUS_DATA_ONLY; dev->cdrom_capacity = dev->ops->get_last_block(dev->local); @@ -2744,7 +2772,7 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) cdrom_toc_dump(dev); #endif - if (!skip_insert) { + if (!skip_insert && (dev->cd_status != CD_STATUS_EMPTY)) { /* Signal media change to the emulated machine. */ cdrom_insert(dev->id); diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index afc70bda7..271a290cb 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -1992,7 +1992,8 @@ static const cdrom_ops_t image_ops = { image_is_dvd, image_has_audio, NULL, - image_close + image_close, + NULL }; /* Public functions. */ diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 82d211896..7c028d7d6 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -271,8 +271,9 @@ typedef struct cdrom_ops_t { uint32_t *info); int (*is_dvd)(const void *local); int (*has_audio)(const void *local); - int (*ext_medium_changed)(void *local); + int (*is_empty)(const void *local); void (*close)(void *local); + void (*load)(const void *local); } cdrom_ops_t; typedef struct cdrom { @@ -423,7 +424,8 @@ extern int cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_ uint8_t *buffer, uint32_t *info); extern void cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer); extern int cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); -extern int cdrom_ext_medium_changed(const cdrom_t *dev); +extern void cdrom_set_empty(cdrom_t *dev); +extern void cdrom_update_status(cdrom_t *dev); extern int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert); extern void cdrom_global_init(void); diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 84abee066..ffe042481 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -219,7 +219,7 @@ #define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 #define ASC_WRITE_PROTECTED 0x27 #define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_CAPACITY_DATA_CHANGED 0x2a #define ASC_INCOMPATIBLE_FORMAT 0x30 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_DATA_PHASE_ERROR 0x4b diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index 9efd67ad6..bddfabb5b 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -40,7 +40,6 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; - int toc_valid; void *handle; char path[256]; } ioctl_t; @@ -77,8 +76,6 @@ ioctl_open_handle(UNUSED(ioctl_t *ioctl)) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) - ioctl->toc_valid = 1; } /* Shared functions. */ @@ -159,6 +156,12 @@ ioctl_has_audio(UNUSED(const void *local)) return 0; } +static int +ioctl_is_empty(const void *local) +{ + return 1; +} + static int ioctl_ext_medium_changed(UNUSED(void *local)) { @@ -186,6 +189,18 @@ ioctl_close(void *local) ioctl->log = NULL; } +static void +ioctl_load(const void *local) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; + + if (ioctl_open_handle((ioctl_t *) ioctl)) { + ioctl_close_handle((ioctl_t *) ioctl); + + ioctl_read_toc((ioctl_t *) ioctl); + } +} + static const cdrom_ops_t ioctl_ops = { ioctl_get_track_info, ioctl_get_raw_track_info, @@ -196,8 +211,9 @@ static const cdrom_ops_t ioctl_ops = { ioctl_read_dvd_structure, ioctl_is_dvd, ioctl_has_audio, - ioctl_ext_medium_changed, - ioctl_close + ioctl_is_empty, + ioctl_close, + ioctl_load }; /* Public functions. */ @@ -218,7 +234,6 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_log(ioctl->log, "Path is %s\n", ioctl->path); ioctl->dev = dev; - ioctl->toc_valid = 0; dev->ops = &ioctl_ops; } diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 24baa257f..13e0ec9a7 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -51,7 +51,10 @@ #include <86box/mouse.h> #include <86box/plat.h> #include <86box/86box.h> +#include <86box/cdrom.h> #include <86box/video.h> +#include +#include extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); @@ -151,72 +154,142 @@ WindowsRawInputFilter::~WindowsRawInputFilter() RegisterRawInputDevices(rid, 2, sizeof(rid[0])); } +static void +notify_drives(ULONG unitmask, int empty) +{ + char p[1024] = { 0 }; + + for (int i = 0; i < 26; ++i) { + if (unitmask & 0x1) { + cdrom_t *dev = NULL; + + sprintf(p, "ioctl://\\\\.\\%c:", 'A' + i); + + for (int i = 0; i < CDROM_NUM; i++) + if (!stricmp(cdrom[i].image_path, p)) { + dev = &(cdrom[i]); + if (empty) + cdrom_set_empty(dev); + else + cdrom_update_status(dev); + // pclog("CD-ROM %i : Drive notified of media %s\n", + // dev->id, empty ? "removal" : "change"); + } + } + + unitmask = unitmask >> 1; + } +} + +static void +device_change(WPARAM wParam, LPARAM lParam) +{ + PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lParam; + + switch(wParam) { + case DBT_DEVICEARRIVAL: + case DBT_DEVICEREMOVECOMPLETE: + /* Check whether a CD or DVD was inserted into a drive. */ + if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) { + PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb; + + if (lpdbv->dbcv_flags & DBTF_MEDIA) + notify_drives(lpdbv->dbcv_unitmask, + (wParam == DBT_DEVICEREMOVECOMPLETE)); + } + break; + + default: + /* + Process other WM_DEVICECHANGE notifications for other + devices or reasons. + */ + break; + } +} + bool WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) { if (eventType == "windows_generic_MSG") { MSG *msg = static_cast(message); - if (msg->message == WM_INPUT) { - - if (window->isActiveWindow() && menus_open == 0) - handle_input((HRAWINPUT) msg->lParam); - else - { - for (auto &w : window->renderers) { - if (w && w->isActiveWindow()) { - handle_input((HRAWINPUT) msg->lParam); - break; + if (msg != nullptr) switch(msg->message) { + case WM_INPUT: + if (window->isActiveWindow() && (menus_open == 0)) + handle_input((HRAWINPUT) msg->lParam); + else { + for (auto &w : window->renderers) { + if (w && w->isActiveWindow()) { + handle_input((HRAWINPUT) msg->lParam); + break; + } } } - } - - return true; - } else if ((msg != nullptr) && (msg->message == WM_SETTINGCHANGE) && - (((void *) msg->lParam) != nullptr) && - (wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) { - if (!windows_is_light_theme()) { - QFile f(":qdarkstyle/dark/darkstyle.qss"); - - if (!f.exists()) { - printf("Unable to set stylesheet, file not found\n"); - } else { - f.open(QFile::ReadOnly | QFile::Text); - QTextStream ts(&f); - qApp->setStyleSheet(ts.readAll()); - } - QTimer::singleShot(1000, [this] () { - BOOL DarkMode = TRUE; - DwmSetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); - window->ui->stackedWidget->switchRenderer((RendererStack::Renderer) vid_api); - for (int i = 1; i < MONITORS_NUM; i++) { - if (window->renderers[i] && !window->renderers[i]->isHidden()) - window->renderers[i]->switchRenderer((RendererStack::Renderer) vid_api); - } - }); - } else { - qApp->setStyleSheet(""); - QTimer::singleShot(1000, [this] () { - BOOL DarkMode = FALSE; - DwmSetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); - }); - } - - QTimer::singleShot(1000, [this] () { - window->resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); - for (int i = 1; i < MONITORS_NUM; i++) { - if (window->renderers[i] && !window->renderers[i]->isHidden()) { - window->resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); - } - } - }); - } - - /* Stop processing of Alt-F4 */ - if (msg->message == WM_SYSKEYDOWN) { - if (msg->wParam == 0x73) { return true; - } + case WM_SETTINGCHANGE: + if ((((void *) msg->lParam) != nullptr) && + (wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) { + + if (!windows_is_light_theme()) { + QFile f(":qdarkstyle/dark/darkstyle.qss"); + + if (!f.exists()) + printf("Unable to set stylesheet, file not found\n"); + else { + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + } + QTimer::singleShot(1000, [this] () { + BOOL DarkMode = TRUE; + auto vid_stack = (RendererStack::Renderer) vid_api; + DwmSetWindowAttribute((HWND) window->winId(), + DWMWA_USE_IMMERSIVE_DARK_MODE, + (LPCVOID) &DarkMode, + sizeof(DarkMode)); + window->ui->stackedWidget->switchRenderer(vid_stack); + for (int i = 1; i < MONITORS_NUM; i++) { + if ((window->renderers[i] != nullptr) && + !window->renderers[i]->isHidden()) + window->renderers[i]->switchRenderer(vid_stack); + } + }); + } else { + qApp->setStyleSheet(""); + QTimer::singleShot(1000, [this] () { + BOOL DarkMode = FALSE; + DwmSetWindowAttribute((HWND) window->winId(), + DWMWA_USE_IMMERSIVE_DARK_MODE, + (LPCVOID) &DarkMode, + sizeof(DarkMode)); + }); + } + + QTimer::singleShot(1000, [this] () { + window->resizeContents(monitors[0].mon_scrnsz_x, + monitors[0].mon_scrnsz_y); + for (int i = 1; i < MONITORS_NUM; i++) { + auto mon = &(monitors[i]); + + if ((window->renderers[i] != nullptr) && + !window->renderers[i]->isHidden()) + window->resizeContentsMonitor(mon->mon_scrnsz_x, + mon->mon_scrnsz_y, + i); + } + }); + } + break; + case WM_SYSKEYDOWN: + /* Stop processing of Alt-F4 */ + if (msg->wParam == 0x73) + return true; + break; + case WM_DEVICECHANGE: + if (msg->hwnd == (HWND) window->winId()) + device_change(msg->wParam, msg->lParam); + break; } } diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 38c553852..621cf0b76 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -32,9 +32,11 @@ #include #include #include +#include <86box/86box.h> #include <86box/cdrom.h> #include <86box/log.h> #include <86box/plat_cdrom_ioctl.h> +#include <86box/scsi_device.h> typedef struct ioctl_t { cdrom_t *dev; @@ -42,7 +44,6 @@ typedef struct ioctl_t { int is_dvd; int has_audio; int32_t tracks_num; - int toc_valid; uint8_t cur_toc[65536]; CDROM_READ_TOC_EX cur_read_toc_ex; int blocks_num; @@ -51,9 +52,8 @@ typedef struct ioctl_t { WCHAR path[256]; } ioctl_t; -static void ioctl_read_toc(ioctl_t *ioctl); -static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format, - uint8_t *buffer, uint32_t *info); +static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format, + uint8_t *buffer, uint32_t *info); #ifdef ENABLE_IOCTL_LOG int ioctl_do_log = ENABLE_IOCTL_LOG; @@ -94,25 +94,6 @@ ioctl_open_handle(ioctl_t *ioctl) return (ioctl->handle != INVALID_HANDLE_VALUE); } -static int -ioctl_load(ioctl_t *ioctl) -{ - int ret = 0; - - if (ioctl_open_handle(ioctl)) { - long size; - DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, - NULL, 0, NULL, 0, - (LPDWORD) &size, NULL); - ret = 1; - ioctl_close_handle(ioctl); - - ioctl_read_toc(ioctl); - } - - return ret; -} - static int ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) { @@ -266,11 +247,8 @@ ioctl_read_raw_toc(ioctl_t *ioctl) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) { - ioctl->toc_valid = 1; - (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); - ioctl_read_raw_toc(ioctl); - } + (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); + ioctl_read_raw_toc(ioctl); } static int @@ -301,8 +279,6 @@ ioctl_is_track_audio(const ioctl_t *ioctl, const uint32_t pos) const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; int ret = 0; - ioctl_read_toc((ioctl_t *) ioctl); - if (ioctl->has_audio && !ioctl->is_dvd) { const int track = ioctl_get_track(ioctl, pos); const int control = rti[track].adr_ctl; @@ -324,8 +300,6 @@ ioctl_get_track_info(const void *local, const uint32_t track, const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; int ret = 1; - ioctl_read_toc((ioctl_t *) ioctl); - if ((track < 1) || (track == 0xaa) || (track > (toc->LastTrack + 1))) { ioctl_log(ioctl->log, "ioctl_get_track_info(%02i)\n", track); ret = 0; @@ -363,8 +337,6 @@ ioctl_is_track_pre(const void *local, const uint32_t sector) const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; int ret = 0; - ioctl_read_toc((ioctl_t *) ioctl); - if (ioctl->has_audio && !ioctl->is_dvd) { const int track = ioctl_get_track(ioctl, sector); const int control = rti[track].adr_ctl; @@ -572,8 +544,6 @@ ioctl_get_last_block(const void *local) const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; uint32_t lb = 0; - ioctl_read_toc((ioctl_t *) ioctl); - for (int c = 0; c <= toc->LastTrack; c++) { const TRACK_DATA *td = &toc->TrackData[c]; const uint32_t address = MSFtoLBA(td->Address[1], td->Address[2], @@ -688,44 +658,80 @@ ioctl_has_audio(const void *local) } static int -ioctl_ext_medium_changed(void *local) +ioctl_is_empty(const void *local) { - ioctl_t * ioctl = (ioctl_t *) local; - const CDROM_TOC *toc = (CDROM_TOC *) ioctl->cur_toc; - const TRACK_DATA *ltd = &toc->TrackData[toc->LastTrack]; - const uint32_t old_addr = *(uint32_t *) ltd->Address; - const int temp = ioctl_read_normal_toc(ioctl, ioctl->cur_toc); - int ret = 0; + typedef struct SCSI_PASS_THROUGH_DIRECT_BUF { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR SenseBuf[64]; + } SCSI_PASS_THROUGH_DIRECT_BUF; - if (temp == 1) { - if (ioctl->toc_valid && ((*(uint32_t *) ltd->Address) != old_addr)) { - /* The TOC has changed. */ - ioctl->toc_valid = 0; - ret = 1; - } + const ioctl_t * ioctl = (const ioctl_t *) local; + unsigned long int unused = 0; + SCSI_PASS_THROUGH_DIRECT_BUF req; - if (!ioctl->toc_valid) { - ioctl->toc_valid = 1; - ioctl_read_raw_toc(ioctl); - } - } else { - /* There has been some kind of error - not a medium change, but a not ready - condition. */ - ret = -1; - } + ioctl_open_handle((ioctl_t *) ioctl); - if (ret == 1) { - if (ioctl->is_dvd) - ioctl->dev->cd_status = CD_STATUS_DVD; - else - ioctl->dev->cd_status = ioctl->has_audio ? CD_STATUS_STOPPED : - CD_STATUS_DATA_ONLY; + memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); + req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + req.spt.PathId = 0; + req.spt.TargetId = 1; + req.spt.Lun = 0; + req.spt.CdbLength = 12; + req.spt.DataIn = SCSI_IOCTL_DATA_IN; + req.spt.SenseInfoLength = sizeof(req.SenseBuf); + req.spt.DataTransferLength = 0; + req.spt.TimeOutValue = 6; + req.spt.DataBuffer = NULL; + req.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_BUF, SenseBuf); - ioctl->dev->cdrom_capacity = ioctl_get_last_block(ioctl); - } else if (ret == -1) - ioctl->dev->cd_status = CD_STATUS_EMPTY; + /* Fill in the CDB. */ + req.spt.Cdb[0] = 0x00; + req.spt.Cdb[1] = 0x00; + req.spt.Cdb[2] = 0x00; + req.spt.Cdb[3] = 0x00; + req.spt.Cdb[4] = 0x00; + req.spt.Cdb[5] = 0x00; + req.spt.Cdb[6] = 0x00; + req.spt.Cdb[7] = 0x00; + req.spt.Cdb[8] = 0x00; + req.spt.Cdb[9] = 0x00; + req.spt.Cdb[10] = 0x00; + req.spt.Cdb[11] = 0x00; - ioctl_log(ioctl->log, "ioctl_ext_medium_changed(): %i\n", ret); + DWORD length = sizeof(SCSI_PASS_THROUGH_DIRECT_BUF); + +#ifdef ENABLE_IOCTL_LOG + uint8_t *cdb = (uint8_t *) req.spt.Cdb; + ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X %02X\n", + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], + cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); +#endif + + int ret = DeviceIoControl(ioctl->handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &req, length, + &req, length, + &unused, NULL); + + ioctl_log(ioctl->log, "ioctl_read_dvd_structure(): ret = %d, " + "req.spt.DataTransferLength = %lu\n", + ret, req.spt.DataTransferLength); + ioctl_log(ioctl->log, "Sense: %08X, %08X\n", req.spt.SenseInfoLength, + req.spt.SenseInfoOffset); + + if (req.spt.SenseInfoLength >= 16) { + uint8_t *sb = (uint8_t *) req.SenseBuf; + /* Return sense to the host as is. */ + ret = ((sb[2] == SENSE_NOT_READY) && (sb[12] == ASC_MEDIUM_NOT_PRESENT)); + ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n", + sb[0], sb[1], sb[ 2], sb[ 3], sb[ 4], sb[ 5], sb[ 6], sb[ 7]); + ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n", + sb[8], sb[9], sb[10], sb[11], sb[12], sb[13], sb[14], sb[15]); + } else + ret = 0; + + ioctl_close_handle((ioctl_t *) ioctl); return ret; } @@ -744,6 +750,22 @@ ioctl_close(void *local) ioctl->log = NULL; } +static void +ioctl_load(const void *local) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; + + if (ioctl_open_handle((ioctl_t *) ioctl)) { + long size; + DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, + NULL, 0, NULL, 0, + (LPDWORD) &size, NULL); + ioctl_close_handle((ioctl_t *) ioctl); + + ioctl_read_toc((ioctl_t *) ioctl); + } +} + static const cdrom_ops_t ioctl_ops = { ioctl_get_track_info, ioctl_get_raw_track_info, @@ -754,8 +776,9 @@ static const cdrom_ops_t ioctl_ops = { ioctl_read_dvd_structure, ioctl_is_dvd, ioctl_has_audio, - ioctl_ext_medium_changed, - ioctl_close + ioctl_is_empty, + ioctl_close, + ioctl_load }; /* Public functions. */ @@ -776,7 +799,6 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); ioctl->dev = dev; - ioctl->toc_valid = 0; dev->ops = &ioctl_ops; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index ff49aef90..04c6532df 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -678,8 +678,13 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; scsi_cdrom_set_callback(dev); return; + case 0x43: + dev->drv->seek_diff = dev->drv->seek_pos + 150; + dev->drv->seek_pos = 0; + fallthrough; case 0x08: case 0x28: + case 0x42: case 0x44: case 0xa8: /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); @@ -693,7 +698,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; fallthrough; case 0x25: - case 0x42 ... 0x44: + // case 0x42 ... 0x44: case 0x51 ... 0x52: case 0xad: case 0xb8 ... 0xb9: @@ -702,6 +707,11 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += 40.0; /* Account for seek time. */ /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ + /* + TODO: This is a bit of a lie - the actual period is closer to + 75 * 2448 bytes per second, because the subchannel data + has to be read as well. + */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; break; @@ -730,7 +740,19 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); - period = period * (double) (dev->packet_len); + switch (cmd) { + default: + period = period * (double) (dev->packet_len); + break; + case 0x42: case 0x44: + /* READ SUBCHANNEL or READ HEADER - period of 1 entire sector. */ + period = period * 2352.0; + break; + case 0x43: + /* READ TOC - period of 175 entire frames. */ + period = period * 150.0 * 2352.0; + break; + } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); dev->callback += period; @@ -1181,25 +1203,6 @@ scsi_cdrom_insert(void *priv) } } -static void -scsi_cdrom_ext_insert(void *priv, int ext_medium_changed) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; - - if ((dev == NULL) || (dev->drv == NULL)) - return; - - if ((dev->drv->ops == NULL) || (ext_medium_changed == -1)) { - dev->unit_attention = 0; - dev->drv->cd_status = CD_STATUS_EMPTY; - scsi_cdrom_log(dev->log, "External media removal\n"); - } else if (ext_medium_changed == 1) { - dev->unit_attention = 0; - dev->drv->cd_status |= CD_STATUS_TRANSITION; - scsi_cdrom_log(dev->log, "External media transition\n"); - } -} - static int scsi_command_check_ready(const scsi_cdrom_t *dev, const uint8_t *cdb) { @@ -1223,7 +1226,6 @@ static int scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) { int ready; - const int ext_medium_changed = cdrom_ext_medium_changed(dev->drv); if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { @@ -1257,9 +1259,6 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) return 0; } - if (ext_medium_changed != 0) - scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); - if ((dev->drv->cd_status == CD_STATUS_PLAYING) || (dev->drv->cd_status == CD_STATUS_PAUSED)) { ready = 1; @@ -1270,13 +1269,10 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE)) ready = 0; else { - if ((ext_medium_changed != 0) || - !(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - scsi_cdrom_log(dev->log, "(ext_medium_changed != 0): scsi_cdrom_insert()\n"); + if (!(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) scsi_cdrom_insert((void *) dev); - } - ready = (dev->drv->cd_status != CD_STATUS_EMPTY) || (ext_medium_changed == -1); + ready = (dev->drv->cd_status != CD_STATUS_EMPTY); } } else ready = (dev->drv->cd_status != CD_STATUS_EMPTY); @@ -1469,10 +1465,6 @@ void scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - const int ext_medium_changed = cdrom_ext_medium_changed(dev->drv); - - if (ext_medium_changed != 0) - scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); if ((dev->drv->cd_status == CD_STATUS_EMPTY) && dev->unit_attention) { /* diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index 9efd67ad6..bddfabb5b 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -40,7 +40,6 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; - int toc_valid; void *handle; char path[256]; } ioctl_t; @@ -77,8 +76,6 @@ ioctl_open_handle(UNUSED(ioctl_t *ioctl)) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) - ioctl->toc_valid = 1; } /* Shared functions. */ @@ -159,6 +156,12 @@ ioctl_has_audio(UNUSED(const void *local)) return 0; } +static int +ioctl_is_empty(const void *local) +{ + return 1; +} + static int ioctl_ext_medium_changed(UNUSED(void *local)) { @@ -186,6 +189,18 @@ ioctl_close(void *local) ioctl->log = NULL; } +static void +ioctl_load(const void *local) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; + + if (ioctl_open_handle((ioctl_t *) ioctl)) { + ioctl_close_handle((ioctl_t *) ioctl); + + ioctl_read_toc((ioctl_t *) ioctl); + } +} + static const cdrom_ops_t ioctl_ops = { ioctl_get_track_info, ioctl_get_raw_track_info, @@ -196,8 +211,9 @@ static const cdrom_ops_t ioctl_ops = { ioctl_read_dvd_structure, ioctl_is_dvd, ioctl_has_audio, - ioctl_ext_medium_changed, - ioctl_close + ioctl_is_empty, + ioctl_close, + ioctl_load }; /* Public functions. */ @@ -218,7 +234,6 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_log(ioctl->log, "Path is %s\n", ioctl->path); ioctl->dev = dev; - ioctl->toc_valid = 0; dev->ops = &ioctl_ops; }