Skip to content

Commit

Permalink
Support for platform eject buttons.
Browse files Browse the repository at this point in the history
  • Loading branch information
saybur committed May 20, 2023
1 parent 82b6cc9 commit 299656a
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 9 deletions.
5 changes: 5 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,11 @@ void platform_poll()
adc_poll();
}

uint8_t platform_get_buttons()
{
return 0;
}

/***********************/
/* Flash reprogramming */
/***********************/
Expand Down
7 changes: 7 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ void platform_reset_watchdog();
// few milliseconds shouldn't disturb SCSI communication.
void platform_poll();

// Returns the state of any platform-specific buttons.
// The returned value should be a mask for buttons 1-8 in bits 0-7 respectively,
// where '1' is a button pressed and '0' is a button released.
// Debouncing logic is left up to the specific implementation.
// This function should return without significantly delay.
uint8_t platform_get_buttons();

// Reinitialize SD card connection and save log from interrupt context.
// This can be used in crash handlers.
void platform_emergency_log_save();
Expand Down
13 changes: 13 additions & 0 deletions lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ void platform_init()
#else
// pin function pup pdown out state fast
gpio_conf(GPIO_EXP_AUDIO, GPIO_FUNC_SPI, true,false, false, true, true);
gpio_conf(GPIO_EXP_SPARE, GPIO_FUNC_SIO, true,false, false, true, false);
// configuration of corresponding SPI unit occurs in audio_setup()
#endif
}
Expand Down Expand Up @@ -618,6 +619,18 @@ void platform_poll()
#endif
}

uint8_t platform_get_buttons()
{
#ifdef ENABLE_AUDIO_OUTPUT
uint8_t pins = 0x00;
// pulled to VCC via resistor, sinking when pressed
if (!gpio_get(GPIO_EXP_SPARE)) pins |= 0x01;
return pins;
#else
return 0;
#endif
}

/*****************************************/
/* Flash reprogramming from bootloader */
/*****************************************/
Expand Down
7 changes: 7 additions & 0 deletions lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ void platform_reset_watchdog();
// few milliseconds shouldn't disturb SCSI communication.
void platform_poll();

// Returns the state of any platform-specific buttons.
// The returned value should be a mask for buttons 1-8 in bits 0-7 respectively,
// where '1' is a button pressed and '0' is a button released.
// Debouncing logic is left up to the specific implementation.
// This function should return without significantly delay.
uint8_t platform_get_buttons();

// Set callback that will be called during data transfer to/from SD card.
// This can be used to implement simultaneous transfer to SCSI bus.
typedef void (*sd_callback_t)(uint32_t bytes_complete);
Expand Down
7 changes: 7 additions & 0 deletions lib/ZuluSCSI_platform_template/ZuluSCSI_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ void platform_poll()

}

// Called periodically to get the state of any buttons installed on the platform.
// If none are installed the below function is fine.
uint8_t platform_get_buttons()
{
return 0;
}

/**********************************************/
/* Mapping from data bytes to GPIO BOP values */
/**********************************************/
Expand Down
7 changes: 7 additions & 0 deletions lib/ZuluSCSI_platform_template/ZuluSCSI_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ void platform_reset_watchdog();
// few milliseconds shouldn't disturb SCSI communication.
void platform_poll();

// Returns the state of any platform-specific buttons.
// The returned value should be a mask for buttons 1-8 in bits 0-7 respectively,
// where '1' is a button pressed and '0' is a button released.
// Debouncing logic is left up to the specific implementation.
// This function should return without significantly delay.
uint8_t platform_get_buttons();

// Set callback that will be called during data transfer to/from SD card.
// This can be used to implement simultaneous transfer to SCSI bus.
typedef void (*sd_callback_t)(uint32_t bytes_complete);
Expand Down
1 change: 1 addition & 0 deletions src/ZuluSCSI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ extern "C" void zuluscsi_main_loop(void)

platform_reset_watchdog();
platform_poll();
diskEjectButtonUpdate(true);

#ifdef PLATFORM_HAS_INITIATOR_MODE
if (platform_is_initiator_mode_enabled())
Expand Down
24 changes: 16 additions & 8 deletions src/ZuluSCSI_cdrom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,18 @@ bool cdromValidateCueSheet(image_config_t &img)
/* Ejection and image switching logic */
/**************************************/

void cdromPerformEject(image_config_t &img)
{
uint8_t target = img.scsiId & 7;
#if ENABLE_AUDIO_OUTPUT
// terminate audio playback if active on this target (MMC-1 Annex C)
audio_stop(target);
#endif
dbgmsg("------ CDROM open tray on ID ", (int)target);
img.ejected = true;
img.cdrom_events = 3; // Media removal
}

// Reinsert any ejected CDROMs on reboot
void cdromReinsertFirstImage(image_config_t &img)
{
Expand Down Expand Up @@ -1232,6 +1244,7 @@ static void doReadCD(uint32_t lba, uint32_t length, uint8_t sector_type,
for (uint32_t idx = 0; idx < length; idx++)
{
platform_poll();
diskEjectButtonUpdate(false);

img.file.seek(offset + idx * trackinfo.sector_length + skip_begin);

Expand All @@ -1247,6 +1260,7 @@ static void doReadCD(uint32_t lba, uint32_t length, uint8_t sector_type,
scsiDev.resetFlag = 1;
}
platform_poll();
diskEjectButtonUpdate(false);
}
if (scsiDev.resetFlag) break;

Expand Down Expand Up @@ -1405,25 +1419,19 @@ extern "C" int scsiCDRomCommand()
uint8_t command = scsiDev.cdb[0];
if (command == 0x1B)
{
#if ENABLE_AUDIO_OUTPUT
// terminate audio playback if active on this target (Annex C)
audio_stop(img.scsiId & 7);
#endif
if ((scsiDev.cdb[4] & 2))
{
// CD-ROM load & eject
int start = scsiDev.cdb[4] & 1;
if (start)
{
dbgmsg("------ CDROM close tray");
dbgmsg("------ CDROM close tray on ID ", (int)(img.scsiId & 7));
img.ejected = false;
img.cdrom_events = 2; // New media
}
else
{
dbgmsg("------ CDROM open tray");
img.ejected = true;
img.cdrom_events = 3; // Media removal
cdromPerformEject(img);
}
}
else
Expand Down
3 changes: 3 additions & 0 deletions src/ZuluSCSI_cdrom.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
// Called by scsi.c from SCSI2SD
extern "C" int scsiCDRomCommand(void);

// Eject the given CD-ROM
void cdromPerformEject(image_config_t &img);

// Reinsert ejected CD-ROM and restart from first image
void cdromReinsertFirstImage(image_config_t &img);

Expand Down
58 changes: 57 additions & 1 deletion src/ZuluSCSI_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,8 @@ static void scsiDiskLoadConfig(int target_idx, const char *section)
img.rightAlignStrings = ini_getbool(section, "RightAlignStrings", 0, CONFIGFILE);
img.prefetchbytes = ini_getl(section, "PrefetchBytes", img.prefetchbytes, CONFIGFILE);
img.reinsert_on_inquiry = ini_getbool(section, "ReinsertCDOnInquiry", 1, CONFIGFILE);

img.ejectButton = ini_getl(section, "EjectButton", 0, CONFIGFILE);

char tmp[32];
memset(tmp, 0, sizeof(tmp));
ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
Expand Down Expand Up @@ -555,6 +556,55 @@ image_config_t &scsiDiskGetImageConfig(int target_idx)
return g_DiskImages[target_idx];
}

static void diskEjectAction(uint8_t buttonId)
{
logmsg("Eject button pressed for channel ", buttonId);
for (uint8_t i = 0; i < S2S_MAX_TARGETS; i++)
{
image_config_t img = g_DiskImages[i];
if (img.ejectButton == buttonId)
{
if (img.deviceType == S2S_CFG_OPTICAL)
{
cdromPerformEject(img);
}
}
}
}

uint8_t diskEjectButtonUpdate(bool immediate)
{
// treat '1' to '0' transitions as eject actions
static uint8_t previous = 0x00;
uint8_t bitmask = platform_get_buttons();
uint8_t ejectors = (previous ^ bitmask) & previous;
previous = bitmask;

// defer ejection until the bus is idle
static uint8_t deferred = 0x00;
if (!immediate)
{
deferred |= ejectors;
return 0;
}
else
{
ejectors |= deferred;
deferred = 0;

if (ejectors)
{
uint8_t mask = 1;
for (uint8_t i = 0; i < 8; i++)
{
if (ejectors & mask) diskEjectAction(i + 1);
mask = mask << 1;
}
}
return ejectors;
}
}

/*******************************/
/* Config handling for SCSI2SD */
/*******************************/
Expand Down Expand Up @@ -1059,6 +1109,7 @@ void diskDataOut()
&& !scsiDev.resetFlag)
{
platform_poll();
diskEjectButtonUpdate(false);

// Figure out how many contiguous bytes are available for writing to SD card.
uint32_t bufsize = sizeof(scsiDev.data);
Expand Down Expand Up @@ -1226,6 +1277,7 @@ void scsiDiskStartRead(uint32_t lba, uint32_t blocks)
while (!scsiIsWriteFinished(NULL))
{
platform_poll();
diskEjectButtonUpdate(false);
}

scsiFinishWrite();
Expand Down Expand Up @@ -1298,6 +1350,7 @@ static void start_dataInTransfer(uint8_t *buffer, uint32_t count)
}

platform_poll();
diskEjectButtonUpdate(false);
}
if (scsiDev.resetFlag) return;

Expand All @@ -1318,6 +1371,7 @@ static void start_dataInTransfer(uint8_t *buffer, uint32_t count)
platform_set_sd_callback(NULL, NULL);

platform_poll();
diskEjectButtonUpdate(false);
}

static void diskDataIn()
Expand Down Expand Up @@ -1372,6 +1426,7 @@ static void diskDataIn()
while (!scsiIsWriteFinished(NULL) && prefetch_sectors > 0 && !scsiDev.resetFlag)
{
platform_poll();
diskEjectButtonUpdate(false);

// Check if prefetch buffer is free
g_disk_transfer.buffer = g_scsi_prefetch.buffer + g_scsi_prefetch.bytes;
Expand Down Expand Up @@ -1402,6 +1457,7 @@ static void diskDataIn()
while (!scsiIsWriteFinished(NULL))
{
platform_poll();
diskEjectButtonUpdate(false);
}

scsiFinishWrite();
Expand Down
9 changes: 9 additions & 0 deletions src/ZuluSCSI_disk.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ struct image_config_t: public S2S_TargetCfg
uint8_t cdrom_events;
bool reinsert_on_inquiry;

// selects a physical button channel that will cause an eject action
// default option of '0' disables this functionality
uint8_t ejectButton;

// For tape drive emulation, current position in blocks
uint32_t tape_pos;

Expand All @@ -70,6 +74,11 @@ struct image_config_t: public S2S_TargetCfg
bool geometrywarningprinted;
};

// Should be polled intermittently to update the platform eject buttons.
// Call with 'true' only if ejections should be performed immediately (typically when not busy)
// Returns a mask of the buttons that registered an 'eject' action.
uint8_t diskEjectButtonUpdate(bool immediate);

// Reset all image configuration to empty reset state, close all images.
void scsiDiskResetImages();

Expand Down

0 comments on commit 299656a

Please sign in to comment.