Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Support inserting and ejecting CD-ROMs by mihaip · Pull Request #222 · dingusdev/dingusppc · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,13 @@ if (APPLE)
# MACOSX_BUNDLE_ICON_FILE "icon.icns"
)

if (NOT IOS)
set_target_properties(dingusppc PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/cmake/DingusPPCInfo.plist.in"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_ID}"
)
endif()

find_library(COCOA_LIBRARY Cocoa)
find_library(IOKIT_LIBRARY IOKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
Expand Down
70 changes: 70 additions & 0 deletions cmake/DingusPPCInfo.plist.in
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>CD-ROM image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.iso-image</string>
<string>com.roxio.disk-image-toast</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Toast disk image</string>
<key>UTTypeIdentifier</key>
<string>com.roxio.disk-image-toast</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>toast</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
25 changes: 25 additions & 0 deletions core/hostevents.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/coresignal.h>

#include <cinttypes>
#include <string>

class WindowEvent {
public:
Expand DownExpand Up@@ -119,6 +120,20 @@ class GamepadEvent {
uint8_t button;
};

enum class CdromInsertionResult {
SUCCESS,
NO_DRIVE,
MEDIA_PRESENT,
IMAGE_OPEN_FAILED,
};

class CdromImageEvent {
public:
std::string image_path;
CdromInsertionResult result = CdromInsertionResult::NO_DRIVE;
bool handled = false;
};

class EventManager {
public:
static EventManager* get_instance() {
Expand All@@ -131,6 +146,9 @@ class EventManager {
void poll_events();
void set_keyboard_locale(uint32_t keyboard_id);
void post_keyboard_state_events();
void post_cdrom_event(CdromImageEvent& event) {
_cdrom_signal.emit(event);
}

template <typename T>
void add_window_handler(T *inst, void (T::*func)(const WindowEvent&)) {
Expand All@@ -152,6 +170,11 @@ class EventManager {
_gamepad_signal.connect_method(inst, func);
}

template <typename T>
void add_cdrom_handler(T* inst, void (T::*func)(CdromImageEvent&)) {
_cdrom_signal.connect_method(inst, func);
}

template <typename T>
void add_post_handler(T *inst, void (T::*func)()) {
_post_signal.connect_method(inst, func);
Expand All@@ -162,6 +185,7 @@ class EventManager {
_mouse_signal.disconnect_all();
_keyboard_signal.disconnect_all();
_gamepad_signal.disconnect_all();
_cdrom_signal.disconnect_all();
_post_signal.disconnect_all();
}

Expand All@@ -179,6 +203,7 @@ class EventManager {
CoreSignal<const MouseEvent&> _mouse_signal;
CoreSignal<const KeyboardEvent&> _keyboard_signal;
CoreSignal<const GamepadEvent&> _gamepad_signal;
CoreSignal<CdromImageEvent&> _cdrom_signal;
CoreSignal<> _post_signal;

uint64_t events_captured = 0;
Expand Down
29 changes: 29 additions & 0 deletions core/hostevents_sdl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,6 +322,35 @@ void EventManager::poll_events() {
}
break;

case SDL_DROPFILE: {
const char* path = event.drop.file;
// TODO: Distinguish CD-ROM and floppy images once dynamic
// floppy insertion is supported.
CdromImageEvent cdrom_event{};
cdrom_event.image_path = path;
this->post_cdrom_event(cdrom_event);

switch (cdrom_event.result) {
case CdromInsertionResult::SUCCESS:
LOG_F(INFO, "Inserted CD-ROM image: %s", path);
break;
case CdromInsertionResult::NO_DRIVE:
LOG_F(ERROR, "Cannot insert CD-ROM image; no CD-ROM drive is available: %s",
path);
break;
case CdromInsertionResult::MEDIA_PRESENT:
LOG_F(ERROR, "Cannot insert CD-ROM image; eject the current media first: %s",
path);
break;
case CdromInsertionResult::IMAGE_OPEN_FAILED:
LOG_F(ERROR, "Cannot insert CD-ROM image: %s", path);
break;
}

SDL_free(event.drop.file);
}
break;

default:
unhandled_events++;
}
Expand Down
3 changes: 2 additions & 1 deletion devices/common/ata/atapicdrom.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,7 +71,8 @@ int AtapiCdrom::device_postinit() {

std::string cdr_image_path = GET_STR_PROP("cdr_img");
if (!cdr_image_path.empty()) {
this->insert_image(cdr_image_path);
if (!this->insert_image(cdr_image_path))
return -1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/ata/atapicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ class AtapiCdrom : public AtapiBaseDevice, public ScsiCdromCmds {
return std::unique_ptr<AtapiCdrom>(new AtapiCdrom("ATAPI-CDROM"));
}

bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

int device_postinit() override;
Expand Down
10 changes: 10 additions & 0 deletions devices/common/scsi/scsi.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -175,6 +175,14 @@ enum ScsiCommand : uint8_t {
READ_CD = 0xBE,
};

/** START STOP UNIT command flags in CDB byte 4. */
namespace ScsiStartStopUnit {
enum : uint8_t {
START = 1 << 0,
LOAD_EJECT = 1 << 1,
};
}

enum ScsiSense : uint8_t {
NO_SENSE = 0x0,
RECOVERED = 0x1,
Expand All@@ -200,8 +208,10 @@ enum ScsiError : uint8_t {
INVALID_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECT = 0x27,
MEDIUM_CHANGED = 0x28,
SAVING_NOT_SUPPORTED = 0x39,
MEDIUM_NOT_PRESENT = 0x3A,
REMOVAL_PREVENTED = 0x53,
};

/** SCSI device types used in INQUIRY. */
Expand Down
13 changes: 8 additions & 5 deletions devices/common/scsi/scsiblockcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,17 +179,20 @@ int ScsiBlockCmds::write() {
}

int ScsiBlockCmds::start_stop_unit() {
if (this->cdb_ptr[4] & 1) {
if (this->cdb_ptr[4] & 2)
if (this->cdb_ptr[4] & ScsiStartStopUnit::START) {
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
LOG_F(INFO, "START_STOP_UNIT: medium load requested");
} else {
if (this->cdb_ptr[4] & 2) {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}
if (this->cdb_ptr[4] & ScsiStartStopUnit::LOAD_EJECT)
this->eject_medium();
}
return ScsiPhase::STATUS;
}

void ScsiBlockCmds::eject_medium() {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
}

int ScsiBlockCmds::read_capacity() {
uint32_t lba = this->get_lba();

Expand Down
1 change: 1 addition & 0 deletions devices/common/scsi/scsiblockcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,7 @@ class ScsiBlockCmds : public ScsiCommonCmds {

protected:
virtual void process_command() override;
virtual void eject_medium();

uint32_t get_lba();

Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsibus.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -354,7 +354,8 @@ void ScsiBus::attach_scsi_devices(const std::string bus_suffix)
gMachineObj->add_device(scsi_device_name,
std::unique_ptr<ScsiCdrom>(scsi_device));
this->register_device(scsi_id, scsi_device);
scsi_device->insert_image(path);
if (!scsi_device->insert_image(path))
ABORT_F("Could not insert CD-ROM image, %s", path.c_str());
}
else {
LOG_F(ERROR, "%s: Too many devices. CD-ROM \"%s\" was not added.",
Expand Down
3 changes: 2 additions & 1 deletion devices/common/scsi/scsicdrom.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ class ScsiCdrom : public ScsiPhysDevice, public ScsiCdromCmds {
}

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->medium_present(); }
uint8_t not_ready_reason() override { return ScsiError::MEDIUM_NOT_PRESENT; }

void mode_select_6(uint8_t param_len);

Expand Down
24 changes: 24 additions & 0 deletions devices/common/scsi/scsicdromcmds.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,30 @@ void ScsiCdromCmds::process_command() {
phy_impl->switch_phase(next_phase);
}

int ScsiCdromCmds::test_unit_ready() {
if (this->consume_media_change()) {
this->sense_key = ScsiSense::UNIT_ATTENTION;
this->asc = ScsiError::MEDIUM_CHANGED;
this->ascq = 0;
phy_impl->set_status(ScsiStatus::CHECK_CONDITION, this->sense_key);
return ScsiPhase::STATUS;
}

return ScsiCommonCmds::test_unit_ready();
}

void ScsiCdromCmds::eject_medium() {
if (this->drive_locked) {
LOG_F(INFO, "START_STOP_UNIT: medium eject prevented");
this->field_ptr_valid = false;
this->bit_ptr_valid = false;
this->illegal_request(ScsiError::REMOVAL_PREVENTED, 2, false);
} else {
LOG_F(INFO, "START_STOP_UNIT: medium eject requested");
this->eject_image();
}
}

int ScsiCdromCmds:: read_toc() {
uint8_t start_track, session_num;
int tot_tracks, resp_len = 0;
Expand Down
2 changes: 2 additions & 0 deletions devices/common/scsi/scsicdromcmds.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,8 @@ class ScsiCdromCmds : public ScsiBlockCmds, public CdromDrive {

protected:
virtual void process_command() override;
int test_unit_ready() override;
void eject_medium() override;

int get_apple_page_49(uint8_t subpage, uint8_t ctrl,
uint8_t *out_ptr, int avail_len);
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,7 +56,7 @@ ScsiHardDisk::ScsiHardDisk(std::string name, int my_id) : ScsiPhysDevice(name, m
}

void ScsiHardDisk::insert_image(std::string filename) {
if (this->set_host_file(filename) < 0)
if (!this->attach_image(filename))
ABORT_F("%s: could not open image file %s", this->name.c_str(), filename.c_str());

this->is_writeable = true;
Expand Down
2 changes: 1 addition & 1 deletion devices/common/scsi/scsihd.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ class ScsiHardDisk : public ScsiPhysDevice, public BlockStorageDevice, public Sc
void process_command() override;

protected:
bool is_device_ready() override { return this->is_ready; }
bool is_device_ready() override { return this->image_attached(); }

void mode_select_6(uint8_t param_len);

Expand Down
37 changes: 30 additions & 7 deletions devices/storage/blockstoragedevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,22 +39,45 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks,
}

BlockStorageDevice::~BlockStorageDevice() {
this->img_file.close();
this->detach_image();
}

int BlockStorageDevice::set_host_file(std::string file_path) {
this->is_ready = false;

bool BlockStorageDevice::attach_image(const std::string& file_path) {
if (!this->img_file.open(file_path))
return -1;
return false;

this->size_bytes = this->img_file.size();
this->is_ready = false;
this->size_bytes = this->img_file.size();
this->remain_size = 0;
this->write_size = 0;
this->data_offset = 0;

this->set_fpos(0);

this->is_ready = true;

return this->set_block_size(this->block_size);
if (this->set_block_size(this->block_size) < 0) {
this->detach_image();
return false;
}

return true;
}

bool BlockStorageDevice::detach_image() {
if (!this->is_ready)
return false;

this->is_ready = false;
this->img_file.close();

this->size_bytes = 0;
this->size_blocks = 0;
this->cur_fpos = 0;
this->write_size = 0;
this->remain_size = 0;

return true;
}

int BlockStorageDevice::set_block_size(const int blk_size) {
Expand Down
Loading
Loading