CD-ROM: IOCTL now detects medium changes without having to read the host drive's TOC on every operation, improves performance.

This commit is contained in:
OBattler
2025-02-03 10:57:19 +01:00
parent a8918de768
commit 35a12e0826
9 changed files with 340 additions and 192 deletions

View File

@@ -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);

View File

@@ -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. */

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 <dbt.h>
#include <strsafe.h>
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<MSG *>(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;
}
}

View File

@@ -32,9 +32,11 @@
#include <stdlib.h>
#include <stddef.h>
#include <wchar.h>
#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;

View File

@@ -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) {
/*

View File

@@ -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;
}