Przeglądaj źródła

Support for platform eject buttons.

saybur 2 lat temu
rodzic
commit
43507dbd32

+ 17 - 0
lib/BlueSCSI_platform_RP2040/BlueSCSI_platform.cpp

@@ -164,7 +164,12 @@ void platform_init()
 #endif
 #else
     //        pin             function       pup   pdown  out    state fast
+<<<<<<< HEAD:lib/BlueSCSI_platform_RP2040/BlueSCSI_platform.cpp
     //gpio_conf(GPIO_EXP_AUDIO, GPIO_FUNC_SPI, true,false, false,  true, true);
+=======
+    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);
+>>>>>>> 299656a1 (Support for platform eject buttons.):lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform.cpp
     // configuration of corresponding SPI unit occurs in audio_setup()
 #endif
 }
@@ -583,6 +588,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   */
 /*****************************************/

+ 7 - 0
lib/BlueSCSI_platform_RP2040/BlueSCSI_platform.h

@@ -72,6 +72,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);

+ 7 - 0
lib/BlueSCSI_platform_template/BlueSCSI_platform.cpp

@@ -59,6 +59,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 */
 /**********************************************/

+ 7 - 0
lib/BlueSCSI_platform_template/BlueSCSI_platform.h

@@ -57,6 +57,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);

+ 1 - 0
src/BlueSCSI.cpp

@@ -641,6 +641,7 @@ extern "C" void bluescsi_main_loop(void)
 
   platform_reset_watchdog();
   platform_poll();
+  diskEjectButtonUpdate(true);
   
 #ifdef PLATFORM_HAS_INITIATOR_MODE
   if (platform_is_initiator_mode_enabled())

+ 16 - 8
src/BlueSCSI_cdrom.cpp

@@ -811,6 +811,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
+    debuglog("------ 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)
 {
@@ -1253,6 +1265,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);
 
@@ -1268,6 +1281,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;
 
@@ -1479,25 +1493,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)
             {
-                debuglog("------ CDROM close tray");
+                debuglog("------ CDROM close tray on ID ", (int)(img.scsiId & 7));
                 img.ejected = false;
                 img.cdrom_events = 2; // New media
             }
             else
             {
-                debuglog("------ CDROM open tray");
-                img.ejected = true;
-                img.cdrom_events = 3; // Media removal
+                cdromPerformEject(img);
             }
         }
         else

+ 3 - 0
src/BlueSCSI_cdrom.h

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

+ 57 - 1
src/BlueSCSI_disk.cpp

@@ -466,7 +466,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", 0, 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);
@@ -544,6 +545,55 @@ image_config_t &scsiDiskGetImageConfig(int target_idx)
     return g_DiskImages[target_idx];
 }
 
+static void diskEjectAction(uint8_t buttonId)
+{
+    log("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 */
 /*******************************/
@@ -1067,6 +1117,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);
@@ -1234,6 +1285,7 @@ void scsiDiskStartRead(uint32_t lba, uint32_t blocks)
             while (!scsiIsWriteFinished(NULL))
             {
                 platform_poll();
+                diskEjectButtonUpdate(false);
             }
 
             scsiFinishWrite();
@@ -1306,6 +1358,7 @@ static void start_dataInTransfer(uint8_t *buffer, uint32_t count)
         }
 
         platform_poll();
+        diskEjectButtonUpdate(false);
     }
     if (scsiDev.resetFlag) return;
 
@@ -1326,6 +1379,7 @@ static void start_dataInTransfer(uint8_t *buffer, uint32_t count)
     platform_set_sd_callback(NULL, NULL);
 
     platform_poll();
+    diskEjectButtonUpdate(false);
 }
 
 static void diskDataIn()
@@ -1380,6 +1434,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;
@@ -1410,6 +1465,7 @@ static void diskDataIn()
         while (!scsiIsWriteFinished(NULL))
         {
             platform_poll();
+            diskEjectButtonUpdate(false);
         }
 
         scsiFinishWrite();

+ 9 - 0
src/BlueSCSI_disk.h

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