|  | @@ -10,6 +10,7 @@
 | 
	
		
			
				|  |  |  #include "BlueSCSI_log.h"
 | 
	
		
			
				|  |  |  #include "BlueSCSI_config.h"
 | 
	
		
			
				|  |  |  #include "BlueSCSI_presets.h"
 | 
	
		
			
				|  |  | +#include "BlueSCSI_cdrom.h"
 | 
	
		
			
				|  |  |  #include "ImageBackingStore.h"
 | 
	
		
			
				|  |  |  #include "ROMDrive.h"
 | 
	
		
			
				|  |  |  #include <minIni.h>
 | 
	
	
		
			
				|  | @@ -145,25 +146,6 @@ bool scsiDiskActivateRomDrive()
 | 
	
		
			
				|  |  |  extern SdFs SD;
 | 
	
		
			
				|  |  |  SdDevice sdDev = {2, 256 * 1024 * 1024 * 2}; /* For SCSI2SD */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -struct image_config_t: public S2S_TargetCfg
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    ImageBackingStore file;
 | 
	
		
			
				|  |  | -    // For CD-ROM drive ejection
 | 
	
		
			
				|  |  | -    bool ejected;
 | 
	
		
			
				|  |  | -    uint8_t cdrom_events;
 | 
	
		
			
				|  |  | -    bool reinsert_on_inquiry;
 | 
	
		
			
				|  |  | -    // Index of image, for when image on-the-fly switching is used for CD drives
 | 
	
		
			
				|  |  | -    int image_index;
 | 
	
		
			
				|  |  | -    // Right-align vendor / product type strings (for Apple)
 | 
	
		
			
				|  |  | -    // Standard SCSI uses left alignment
 | 
	
		
			
				|  |  | -    // This field uses -1 for default when field is not set in .ini
 | 
	
		
			
				|  |  | -    int rightAlignStrings;
 | 
	
		
			
				|  |  | -    // Maximum amount of bytes to prefetch
 | 
	
		
			
				|  |  | -    int prefetchbytes;
 | 
	
		
			
				|  |  | -    // Warning about geometry settings
 | 
	
		
			
				|  |  | -    bool geometrywarningprinted;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static image_config_t g_DiskImages[S2S_MAX_TARGETS];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void scsiDiskResetImages()
 | 
	
	
		
			
				|  | @@ -392,6 +374,24 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
 | 
	
		
			
				|  |  |              debuglog("---- Read prefetch enabled: ", (int)img.prefetchbytes, " bytes");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        if (img.deviceType == S2S_CFG_OPTICAL &&
 | 
	
		
			
				|  |  | +            strncasecmp(filename + strlen(filename) - 4, ".bin", 4) == 0)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            char cuesheetname[MAX_FILE_PATH + 1] = {0};
 | 
	
		
			
				|  |  | +            strncpy(cuesheetname, filename, strlen(filename) - 4);
 | 
	
		
			
				|  |  | +            strlcat(cuesheetname, ".cue", sizeof(cuesheetname));
 | 
	
		
			
				|  |  | +            img.cuesheetfile = SD.open(cuesheetname, O_RDONLY);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (img.cuesheetfile.isOpen())
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                log("---- Found CD-ROM CUE sheet at ", cuesheetname);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                log("---- No CUE sheet found at ", cuesheetname, ", using as plain binary image");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          return true;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -469,9 +469,9 @@ static void scsiDiskLoadConfig(int target_idx, const char *section)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Check if image file name is overridden in config
 | 
	
		
			
				|  |  | -static bool get_image_name(int target_idx, char *buf, size_t buflen)
 | 
	
		
			
				|  |  | +bool scsiDiskGetImageNameFromConfig(image_config_t &img, char *buf, size_t buflen)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    image_config_t &img = g_DiskImages[target_idx];
 | 
	
		
			
				|  |  | +    int target_idx = img.scsiId & 7;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      char section[6] = "SCSI0";
 | 
	
		
			
				|  |  |      section[4] = '0' + target_idx;
 | 
	
	
		
			
				|  | @@ -499,9 +499,9 @@ void scsiDiskLoadConfig(int target_idx)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      // Check if we have image specified by name
 | 
	
		
			
				|  |  |      char filename[MAX_FILE_PATH];
 | 
	
		
			
				|  |  | -    if (get_image_name(target_idx, filename, sizeof(filename)))
 | 
	
		
			
				|  |  | +    image_config_t &img = g_DiskImages[target_idx];
 | 
	
		
			
				|  |  | +    if (scsiDiskGetImageNameFromConfig(img, filename, sizeof(filename)))
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        image_config_t &img = g_DiskImages[target_idx];
 | 
	
		
			
				|  |  |          int blocksize = (img.deviceType == S2S_CFG_OPTICAL) ? 2048 : 512;
 | 
	
		
			
				|  |  |          log("-- Opening ", filename, " for id:", target_idx, ", specified in " CONFIGFILE);
 | 
	
		
			
				|  |  |          scsiDiskOpenHDDImage(target_idx, filename, target_idx, 0, blocksize);
 | 
	
	
		
			
				|  | @@ -521,6 +521,12 @@ bool scsiDiskCheckAnyImagesConfigured()
 | 
	
		
			
				|  |  |      return false;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +image_config_t &scsiDiskGetImageConfig(int target_idx)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    assert(target_idx >= 0 && target_idx < S2S_MAX_TARGETS);
 | 
	
		
			
				|  |  | +    return g_DiskImages[target_idx];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /*******************************/
 | 
	
		
			
				|  |  |  /* Config handling for SCSI2SD */
 | 
	
		
			
				|  |  |  /*******************************/
 | 
	
	
		
			
				|  | @@ -811,57 +817,6 @@ static void doReadCapacity()
 | 
	
		
			
				|  |  |  /* TestUnitReady command */
 | 
	
		
			
				|  |  |  /*************************/
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// Check if we have multiple CD-ROM images to cycle when drive is ejected.
 | 
	
		
			
				|  |  | -static bool checkNextCDImage()
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    // Check if we have a next image to load, so that drive is closed next time the host asks.
 | 
	
		
			
				|  |  | -    image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
 | 
	
		
			
				|  |  | -    img.image_index++;
 | 
	
		
			
				|  |  | -    char filename[MAX_FILE_PATH];
 | 
	
		
			
				|  |  | -    int target_idx = img.scsiId & 7;
 | 
	
		
			
				|  |  | -    if (!get_image_name(target_idx, filename, sizeof(filename)))
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        img.image_index = 0;
 | 
	
		
			
				|  |  | -        get_image_name(target_idx, filename, sizeof(filename));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (filename[0] != '\0')
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        log("Switching to next CD-ROM image for ", target_idx, ": ", filename);
 | 
	
		
			
				|  |  | -        image_config_t &img = g_DiskImages[target_idx];
 | 
	
		
			
				|  |  | -        img.file.close();
 | 
	
		
			
				|  |  | -        bool status = scsiDiskOpenHDDImage(target_idx, filename, target_idx, 0, 2048);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (status)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            img.ejected = false;
 | 
	
		
			
				|  |  | -            img.cdrom_events = 2; // New media
 | 
	
		
			
				|  |  | -            return true;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return false;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// Reinsert any ejected CDROMs on reboot
 | 
	
		
			
				|  |  | -static void reinsertCDROM(image_config_t &img)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    if (img.image_index > 0)
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        // Multiple images for this drive, force restart from first one
 | 
	
		
			
				|  |  | -        debuglog("---- Restarting from first CD-ROM image");
 | 
	
		
			
				|  |  | -        img.image_index = 9;
 | 
	
		
			
				|  |  | -        checkNextCDImage();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    else if (img.ejected)
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        // Reinsert the single image
 | 
	
		
			
				|  |  | -        debuglog("---- Closing CD-ROM tray");
 | 
	
		
			
				|  |  | -        img.ejected = false;
 | 
	
		
			
				|  |  | -        img.cdrom_events = 2; // New media
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static int doTestUnitReady()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      int ready = 1;
 | 
	
	
		
			
				|  | @@ -884,7 +839,7 @@ static int doTestUnitReady()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // We are now reporting to host that the drive is open.
 | 
	
		
			
				|  |  |          // Simulate a "close" for next time the host polls.
 | 
	
		
			
				|  |  | -        checkNextCDImage();
 | 
	
		
			
				|  |  | +        cdromSwitchNextImage(img);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      else if (unlikely(!(blockDev.state & DISK_PRESENT)))
 | 
	
		
			
				|  |  |      {
 | 
	
	
		
			
				|  | @@ -905,50 +860,6 @@ static int doTestUnitReady()
 | 
	
		
			
				|  |  |      return ready;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void doGetEventStatusNotification(bool immed)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!immed)
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        // Asynchronous notification not supported
 | 
	
		
			
				|  |  | -        scsiDev.status = CHECK_CONDITION;
 | 
	
		
			
				|  |  | -        scsiDev.target->sense.code = ILLEGAL_REQUEST;
 | 
	
		
			
				|  |  | -        scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 | 
	
		
			
				|  |  | -        scsiDev.phase = STATUS;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    else if (img.cdrom_events)
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        scsiDev.data[0] = 0;
 | 
	
		
			
				|  |  | -        scsiDev.data[1] = 6; // EventDataLength
 | 
	
		
			
				|  |  | -        scsiDev.data[2] = 0x04; // Media status events
 | 
	
		
			
				|  |  | -        scsiDev.data[3] = 0x04; // Supported events
 | 
	
		
			
				|  |  | -        scsiDev.data[4] = img.cdrom_events;
 | 
	
		
			
				|  |  | -        scsiDev.data[5] = 0x01; // Power status
 | 
	
		
			
				|  |  | -        scsiDev.data[6] = 0; // Start slot
 | 
	
		
			
				|  |  | -        scsiDev.data[7] = 0; // End slot
 | 
	
		
			
				|  |  | -        scsiDev.dataLen = 8;
 | 
	
		
			
				|  |  | -        scsiDev.phase = DATA_IN;
 | 
	
		
			
				|  |  | -        img.cdrom_events = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (img.ejected)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            // We are now reporting to host that the drive is open.
 | 
	
		
			
				|  |  | -            // Simulate a "close" for next time the host polls.
 | 
	
		
			
				|  |  | -            checkNextCDImage();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    else
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        scsiDev.data[0] = 0;
 | 
	
		
			
				|  |  | -        scsiDev.data[1] = 2; // EventDataLength
 | 
	
		
			
				|  |  | -        scsiDev.data[2] = 0x00; // Media status events
 | 
	
		
			
				|  |  | -        scsiDev.data[3] = 0x04; // Supported events
 | 
	
		
			
				|  |  | -        scsiDev.dataLen = 4;
 | 
	
		
			
				|  |  | -        scsiDev.phase = DATA_IN;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /****************/
 | 
	
		
			
				|  |  |  /* Seek command */
 | 
	
		
			
				|  |  |  /****************/
 | 
	
	
		
			
				|  | @@ -1507,24 +1418,8 @@ int scsiDiskCommand()
 | 
	
		
			
				|  |  |          // Enable or disable media access operations.
 | 
	
		
			
				|  |  |          //int immed = scsiDev.cdb[1] & 1;
 | 
	
		
			
				|  |  |          int start = scsiDev.cdb[4] & 1;
 | 
	
		
			
				|  |  | -	    int loadEject = scsiDev.cdb[4] & 2;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if (loadEject && img.deviceType == S2S_CFG_OPTICAL)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            if (start)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                debuglog("------ CDROM close tray");
 | 
	
		
			
				|  |  | -                img.ejected = false;
 | 
	
		
			
				|  |  | -                img.cdrom_events = 2; // New media
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                debuglog("------ CDROM open tray");
 | 
	
		
			
				|  |  | -                img.ejected = true;
 | 
	
		
			
				|  |  | -                img.cdrom_events = 3; // Media removal
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        else if (start)
 | 
	
		
			
				|  |  | +        if (start)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              scsiDev.target->started = 1;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -1538,11 +1433,6 @@ int scsiDiskCommand()
 | 
	
		
			
				|  |  |          // TEST UNIT READY
 | 
	
		
			
				|  |  |          doTestUnitReady();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    else if (command == 0x4A)
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        bool immed = scsiDev.cdb[1] & 1;
 | 
	
		
			
				|  |  | -        doGetEventStatusNotification(immed);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |      else if (unlikely(!doTestUnitReady()))
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          // Status and sense codes already set by doTestUnitReady
 | 
	
	
		
			
				|  | @@ -1765,7 +1655,7 @@ void scsiDiskPoll()
 | 
	
		
			
				|  |  |              image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
 | 
	
		
			
				|  |  |              if (img.deviceType == S2S_CFG_OPTICAL && img.reinsert_on_inquiry)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                reinsertCDROM(img);
 | 
	
		
			
				|  |  | +                cdromReinsertFirstImage(img);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1793,7 +1683,7 @@ void scsiDiskReset()
 | 
	
		
			
				|  |  |          image_config_t &img = g_DiskImages[i];
 | 
	
		
			
				|  |  |          if (img.deviceType == S2S_CFG_OPTICAL)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            reinsertCDROM(img);
 | 
	
		
			
				|  |  | +            cdromReinsertFirstImage(img);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |