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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user