Procházet zdrojové kódy

Lots of bug fixing, and 4.7 merges

Michael McMaster před 8 roky
rodič
revize
3d75cda2c5

+ 3 - 2
lib/SCSI2SD/CHANGELOG

@@ -1,7 +1,8 @@
-2016100X		?
+20170329		6.1.0
 	- Enable synchronous transfers on SCSI1 hosts
 	- Support 4MB/s sync transfers for Amiga A590 (WD33C93)
-	- Faster SD performance, but cannot use USB + SD at the same time.
+	- Merge v4.7 release changes, excluding custom mode/inquiry pages
+	- various bug fixes
 
 20161006		6.0.13
 	- Fixed SCSI timing issue

+ 1 - 0
lib/SCSI2SD/Makefile

@@ -148,6 +148,7 @@ SRC = \
 	src/firmware/tape.c \
 	src/firmware/time.c \
 	src/firmware/trace.c \
+	src/firmware/vendor.c \
 	${USBCOMPOSITE_SRC}
 
 build/firmware.elf: $(SRC) rtl/fpga_bitmap.o $(STM32OBJS)

+ 15 - 2
lib/SCSI2SD/include/scsi2sd.h

@@ -79,9 +79,20 @@ typedef enum
 typedef enum
 {
 	S2S_CFG_QUIRKS_NONE,
-	S2S_CFG_QUIRKS_APPLE
+	S2S_CFG_QUIRKS_APPLE,
+	S2S_CFG_QUIRKS_OMTI
 } S2S_CFG_QUIRKS;
 
+typedef enum
+{
+	S2S_CFG_SPEED_NoLimit,
+	S2S_CFG_SPEED_ASYNC_15,
+	S2S_CFG_SPEED_ASYNC_33,
+	S2S_CFG_SPEED_ASYNC_50,
+	S2S_CFG_SPEED_SYNC_5,
+	S2S_CFG_SPEED_SYNC_10
+} S2S_CFG_SPEED;
+
 typedef struct __attribute__((packed))
 {
 	// bits 7 -> 3 = S2S_CFG_TARGET_FLAGS
@@ -122,7 +133,9 @@ typedef struct __attribute__((packed))
 	uint8_t selectionDelay; // milliseconds. 255 = auto
 	uint8_t flags6; // S2S_CFG_FLAGS6
 
-	uint8_t reserved[120]; // Pad out to 128 bytes
+	uint8_t scsiSpeed;
+
+	uint8_t reserved[119]; // Pad out to 128 bytes
 } S2S_BoardCfg;
 
 typedef enum

binární
lib/SCSI2SD/rtl/fpga_bitmap.o


+ 3 - 3
lib/SCSI2SD/src/firmware/config.c

@@ -38,7 +38,7 @@
 
 #include <string.h>
 
-static const uint16_t FIRMWARE_VERSION = 0x060E;
+static const uint16_t FIRMWARE_VERSION = 0x0610;
 
 // 1 flash row
 static const uint8_t DEFAULT_CONFIG[128] =
@@ -220,9 +220,9 @@ debugCommand()
 	response[26] = blockDev.state;
 	response[27] = scsiDev.lastSenseASC >> 8;
 	response[28] = scsiDev.lastSenseASC;
-	response[29] = *SCSI_STS_DBX;
+	response[29] = *SCSI_STS_DBX & 0xff; // What we've read
 	response[30] = LastTrace;
-	response[31] = 0; // Unused
+	response[31] = *SCSI_STS_DBX >> 8; // What we're writing
 	hidPacket_send(response, sizeof(response));
 }
 

+ 2 - 0
lib/SCSI2SD/src/firmware/disk.c

@@ -703,11 +703,13 @@ void scsiDiskPoll()
 			uint32_t sectors =
 				rem < maxSectors ? rem : maxSectors;
 			scsiRead(&scsiDev.data[0], sectors * SD_SECTOR_SIZE, &parityError);
+
 			if (!parityError)
 			{
 				sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);
 			}
 			i += sectors;
+
 #if 0
 			// Wait for the next DMA interrupt. It's beneficial to halt the
 			// processor to give the DMA controller more memory bandwidth to

+ 39 - 5
lib/SCSI2SD/src/firmware/scsi.c

@@ -29,6 +29,7 @@
 //#include "debug.h"
 #include "tape.h"
 #include "mo.h"
+#include "vendor.h"
 
 #include <string.h>
 
@@ -64,6 +65,7 @@ static void enter_BusFree()
 	}
 #endif
 
+
 	scsiEnterBusFree();
 
 	// Wait for the initiator to cease driving signals
@@ -134,6 +136,17 @@ void process_Status()
 	uint8_t message;
 
 	uint8_t control = scsiDev.cdb[scsiDev.cdbLen - 1];
+
+	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
+	{
+		// OMTI non-standard LINK control
+		if (control & 0x01)
+		{
+			scsiDev.phase = COMMAND;
+			return;
+		}
+	}
+
 	if ((scsiDev.status == GOOD) && (control & 0x01))
 	{
 		// Linked command.
@@ -151,6 +164,12 @@ void process_Status()
 	{
 		message = MSG_COMMAND_COMPLETE;
 	}
+
+	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
+	{
+		scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5;
+	}
+
 	scsiWriteByte(scsiDev.status);
 
 	scsiDev.lastStatus = scsiDev.status;
@@ -388,7 +407,7 @@ static void process_Command()
 	{
 		scsiReadBuffer();
 	}
-	else if (!scsiModeCommand())
+	else if (!scsiModeCommand() && !scsiVendorCommand())
 	{
 		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 		scsiDev.target->sense.asc = INVALID_COMMAND_OPERATION_CODE;
@@ -765,7 +784,9 @@ static void process_MessageOut()
 			int transferPeriod = extmsg[1];
 			int offset = extmsg[2];
 
-			if ((transferPeriod < scsiDev.minSyncPeriod) ||
+			if ((
+					(transferPeriod > 0) &&
+					(transferPeriod < scsiDev.minSyncPeriod)) ||
 				(scsiDev.minSyncPeriod == 0))
 			{
 				scsiDev.minSyncPeriod = transferPeriod;
@@ -775,7 +796,9 @@ static void process_MessageOut()
 				// Amiga A590 (WD33C93 chip) only does 3.5MB/s sync
 				// After 80 we start to run out of bits in the fpga timing
 				// register.
-				(transferPeriod == 0))
+				(transferPeriod == 0) ||
+				((scsiDev.boardCfg.scsiSpeed != S2S_CFG_SPEED_NoLimit) &&
+					(scsiDev.boardCfg.scsiSpeed <= S2S_CFG_SPEED_ASYNC_50)))
 			{
 				scsiDev.target->syncOffset = 0;
 				scsiDev.target->syncPeriod = 0;
@@ -791,11 +814,22 @@ static void process_MessageOut()
 				{
 					scsiDev.target->syncPeriod = 12; // 50ns, 20MB/s
 				}
-				else */if (transferPeriod <= 25)
+				else */if (transferPeriod <= 25 &&
+					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
+						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
 				{
 					scsiDev.target->syncPeriod = 25; // 100ns, 10MB/s
-				} else {
+
+				} else if (transferPeriod < 50 &&
+					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
+						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
+				{
+					scsiDev.target->syncPeriod = transferPeriod;
+				} else if (transferPeriod >= 50)
+				{
 					scsiDev.target->syncPeriod = transferPeriod;
+				} else {
+					scsiDev.target->syncPeriod = 50;
 				}
 			}
 

+ 93 - 50
lib/SCSI2SD/src/firmware/scsiPhy.c

@@ -28,45 +28,53 @@
 
 #include <string.h>
 
-// Time until we consider ourselves selected
-// 400ns at 108MHz
-#define SCSI_DEFAULT_SELECTION 43
-#define SCSI_FAST_SELECTION 5
+static uint8_t asyncTimings[][4] =
+{
+/* Speed,    Assert,    Deskew,    Hold,    Glitch */
+{/*1.5MB/s*/ 28,        18,        13,      13},
+{/*3.3MB/s*/ 13,        6,         6,       13},
+{/*5MB/s*/   9,         6,         6,       6} // 80ns
+};
 
-// async.
-// Assumes a 108MHz fpga clock.
-// 2:0 Deskew count, 55ns
-// 6:4 Hold count, 53ns
-// 3:0 Assertion count, 80ns
-#define SCSI_DEFAULT_DESKEW 0x6
-#define SCSI_DEFAULT_TIMING ((0x6 << 4) | 0x9)
+#define SCSI_ASYNC_15 0
+#define SCSI_ASYNC_33 1
+#define SCSI_ASYNC_50 2
 
-// 3.125MB/s (80 period) to < 10MB/s sync
-// Assumes a 108MHz fpga clock. (9 ns)
-// (((period * 4) / 2) * 0.8) / 9
-// Done using 3 fixed point math.
-// 2:0 Deskew count, 55ns normal, or 25ns if faster than 5.5MB/s
-// 6:4 Hold count, 53ns normal, or 33ns if faster than 5.5MB/s
-// 3:0 Assertion count, variable
-#define SCSI_SYNC_DESKEW(period) (period < 45 ? SCSI_FAST10_DESKEW : SCSI_DEFAULT_DESKEW)
-#define SCSI_SYNC_TIMING(period) (((period < 45 ? 0x4 : 0x6) << 4) | ((((((int)period) * 177) + 750)/1000) & 0xF))
+// 5MB/s synchronous timing
+#define SCSI_FAST5_DESKEW 6 // 55ns
+#define SCSI_FAST5_HOLD 6 // 53ns
 
-// 10MB/s
+// 10MB/s synchronous timing
 // 2:0 Deskew count, 25ns
 // 6:4 Hold count, 33ns
 // 3:0 Assertion count, 30ns
 // We want deskew + hold + assert + 3 to add up to 11 clocks
 // the fpga code has 1 clock of overhead when transitioning from deskew to
 // assert to hold
-#define SCSI_FAST10_DESKEW 2
-#define SCSI_FAST10_TIMING ((0x3 << 4) | 0x3)
 
-// 20MB/s
-// 2:0 Deskew count, 12ns
-// 6:4 Hold count, 17ns
-// 3:0 Assertion count, 15ns
-#define SCSI_FAST20_DESKEW 1
-#define SCSI_FAST20_TIMING ((0x2 << 4) | 0x2)
+#define SCSI_FAST10_DESKEW 2 // 25ns
+#define SCSI_FAST10_HOLD 3 // 33ns
+#define SCSI_FAST10_ASSERT 3 // 30ns
+
+#define syncDeskew(period) ((period) < 45 ? \
+	SCSI_FAST10_DESKEW : SCSI_FAST5_DESKEW)
+
+#define syncHold(period) ((period) < 45 ? \
+	((period) == 25 ? SCSI_FAST10_HOLD : 4) /* 25ns/33ns */\
+	: SCSI_FAST5_HOLD)
+
+
+// 3.125MB/s (80 period) to < 10MB/s sync
+// Assumes a 108MHz fpga clock. (9 ns)
+// (((period * 4) / 2) * 0.8) / 9
+// Done using 3 fixed point math.
+// 3:0 Assertion count, variable
+#define syncAssertion(period) ((((((int)period) * 177) + 750)/1000) & 0xF)
+
+// Time until we consider ourselves selected
+// 400ns at 108MHz
+#define SCSI_DEFAULT_SELECTION 43
+#define SCSI_FAST_SELECTION 5
 
 // Private DMA variables.
 static int dmaInProgress = 0;
@@ -440,6 +448,29 @@ void scsiEnterBusFree()
 	*SCSI_CTRL_PHASE = 0;
 }
 
+static void
+scsiSetTiming(
+	uint8_t assertClocks,
+	uint8_t deskew,
+	uint8_t hold,
+	uint8_t glitch)
+{
+	*SCSI_CTRL_DESKEW = ((hold & 7) << 5) | (deskew & 0x1F);
+	*SCSI_CTRL_TIMING = (assertClocks & 0x3F);
+	*SCSI_CTRL_TIMING3 = (glitch & 0xF);
+}
+
+static void
+scsiSetDefaultTiming()
+{
+	const uint8_t* asyncTiming = asyncTimings[3];
+	scsiSetTiming(
+		asyncTiming[0],
+		asyncTiming[1],
+		asyncTiming[2],
+		asyncTiming[3]);
+}
+
 void scsiEnterPhase(int phase)
 {
 	// ANSI INCITS 362-2002 SPI-3 10.7.1:
@@ -458,22 +489,18 @@ void scsiEnterPhase(int phase)
 		if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&
 			scsiDev.target->syncOffset)
 		{
-			if (scsiDev.target->syncPeriod == 12)
+			
+			if (scsiDev.target->syncPeriod <= 25)
 			{
-				// SCSI2 FAST-20 Timing. 20MB/s.
-				*SCSI_CTRL_DESKEW = SCSI_FAST20_DESKEW;
-				*SCSI_CTRL_TIMING = SCSI_FAST20_TIMING;
-			}
-			else if (scsiDev.target->syncPeriod == 25)
-			{
-				// SCSI2 FAST Timing. 10MB/s.
-				*SCSI_CTRL_DESKEW = SCSI_FAST10_DESKEW;
-				*SCSI_CTRL_TIMING = SCSI_FAST10_TIMING;
+				scsiSetTiming(SCSI_FAST10_ASSERT, SCSI_FAST10_DESKEW, SCSI_FAST10_HOLD, 1);
 			}
 			else
 			{
-				*SCSI_CTRL_DESKEW = SCSI_SYNC_DESKEW(scsiDev.target->syncPeriod);
-				*SCSI_CTRL_TIMING = SCSI_SYNC_TIMING(scsiDev.target->syncPeriod);
+				scsiSetTiming(
+					syncAssertion(scsiDev.target->syncPeriod),
+					syncDeskew(scsiDev.target->syncPeriod),
+					syncHold(scsiDev.target->syncPeriod),
+					scsiDev.target->syncPeriod < 45 ? 1 : 5);
 			}
 
 			// See note 26 in SCSI 2 standard: SCSI 1 implementations may assume
@@ -487,12 +514,29 @@ void scsiEnterPhase(int phase)
 			} else {
 				*SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
 			}
-		} else {
+		}
+		else
+		{
+
 			*SCSI_CTRL_SYNC_OFFSET = 0;
+			const uint8_t* asyncTiming;
+
+			if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit ||
+				scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_ASYNC_50) {
+
+				asyncTiming = asyncTimings[SCSI_ASYNC_50];
+			} else if (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_ASYNC_33) {
 
-			// 5MB/s Timing
-			*SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
-			*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+				asyncTiming = asyncTimings[SCSI_ASYNC_33];
+	
+			} else {
+				asyncTiming = asyncTimings[SCSI_ASYNC_15];
+			}
+			scsiSetTiming(
+				asyncTiming[0],
+				asyncTiming[1],
+				asyncTiming[2],
+				asyncTiming[3]);
 		}
 
 		*SCSI_CTRL_PHASE = newPhase;
@@ -527,8 +571,7 @@ void scsiPhyReset()
 	*SCSI_CTRL_DBX = 0;
 
 	*SCSI_CTRL_SYNC_OFFSET = 0;
-	*SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
-	*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+	scsiSetDefaultTiming();
 
 	// DMA Benchmark code
 	// Currently 11MB/s.
@@ -638,8 +681,7 @@ void scsiPhyInit()
 	*SCSI_CTRL_DBX = 0;
 
 	*SCSI_CTRL_SYNC_OFFSET = 0;
-	*SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
-	*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+	scsiSetDefaultTiming();
 
 	*SCSI_CTRL_SEL_TIMING = SCSI_DEFAULT_SELECTION;
 
@@ -725,7 +767,8 @@ int scsiSelfTest()
 	{
 		*SCSI_CTRL_DBX = i;
 		busSettleDelay();
-		if (*SCSI_STS_DBX != (i & 0xff))
+		// STS_DBX is 16 bit!
+		if ((*SCSI_STS_DBX & 0xff) != (i & 0xff))
 		{
 			result |= 1;
 		}

+ 8 - 3
lib/SCSI2SD/src/firmware/scsiPhy.h

@@ -26,8 +26,9 @@
 #define SCSI_DATA_CNT_SET ((volatile uint8_t*)0x6000000C)
 #define SCSI_CTRL_DBX ((volatile uint8_t*)0x6000000E)
 #define SCSI_CTRL_SYNC_OFFSET ((volatile uint8_t*)0x60000010)
-#define SCSI_CTRL_DESKEW ((volatile uint8_t*)0x60000012)
-#define SCSI_CTRL_TIMING ((volatile uint8_t*)0x60000014)
+#define SCSI_CTRL_DESKEW ((volatile uint8_t*)0x60000012)// Timing
+#define SCSI_CTRL_TIMING ((volatile uint8_t*)0x60000014)//Timing2
+#define SCSI_CTRL_TIMING3 ((volatile uint8_t*)0x6000001A)//Timing3
 #define SCSI_CTRL_FLAGS ((volatile uint8_t*)0x60000016)
 #define SCSI_CTRL_FLAGS_DISABLE_GLITCH 0x1
 #define SCSI_CTRL_FLAGS_ENABLE_PARITY 0x2
@@ -38,7 +39,11 @@
 #define SCSI_STS_FIFO_COMPLETE ((volatile uint8_t*)0x60000024)
 #define SCSI_STS_SELECTED ((volatile uint8_t*)0x60000026)
 #define SCSI_STS_SCSI ((volatile uint8_t*)0x60000028)
-#define SCSI_STS_DBX ((volatile uint8_t*)0x6000002A)
+
+// top 8 bits = data we're writing.
+// bottom 8 bits = data we're reading
+#define SCSI_STS_DBX ((volatile uint16_t*)0x6000002A)
+
 #define SCSI_STS_PARITY_ERR ((volatile uint8_t*)0x6000002C)
 
 #define SCSI_FIFO_DATA ((volatile uint16_t*)0x60000040)

+ 1 - 1
lib/SCSI2SD/src/firmware/time.h

@@ -24,7 +24,7 @@ uint32_t s2s_getTime_ms(void); // Returns milliseconds since init
 uint32_t s2s_diffTime_ms(uint32_t start, uint32_t end);
 uint32_t s2s_elapsedTime_ms(uint32_t since);
 
-#define s2s_cpu_freq 120000000LL
+#define s2s_cpu_freq 108000000LL
 #define s2s_delay_ms(delay) s2s_delay_clocks((delay) * (s2s_cpu_freq / 1000))
 #define s2s_delay_us(delay) s2s_delay_clocks((delay) * (s2s_cpu_freq / 1000000))
 void s2s_delay_clocks(uint32_t delay);

+ 23 - 34
lib/SCSI2SD/src/scsi2sd-util6/BoardPanel.cc

@@ -53,7 +53,7 @@ BoardPanel::BoardPanel(wxWindow* parent, const S2S_BoardCfg& initialConfig) :
 	myParent(parent),
 	myDelayValidator(new wxIntegerValidator<uint8_t>)
 {
-	wxFlexGridSizer *fgs = new wxFlexGridSizer(11, 2, 9, 25);
+	wxFlexGridSizer *fgs = new wxFlexGridSizer(13, 2, 9, 25);
 
 	fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
 	myTermCtrl =
@@ -64,6 +64,26 @@ BoardPanel::BoardPanel(wxWindow* parent, const S2S_BoardCfg& initialConfig) :
 	myTermCtrl->SetToolTip(_("Enable active terminator. Both ends of the SCSI chain must be terminated."));
 	fgs->Add(myTermCtrl);
 
+	fgs->Add(new wxStaticText(this, wxID_ANY, _("SCSI Speed Limit")));
+	wxString speeds[] = {
+		wxT("No limit"),
+		wxT("Async, 1.5MB/s"),
+		wxT("Async, 3.3MB/s"),
+		wxT("Async, 5 MB/s"),
+		wxT("Sync, 5 MB/s")};
+
+	myScsiSpeedCtrl =
+		new wxChoice(
+			this,
+			ID_scsiSpeedCtrl,
+			wxDefaultPosition,
+			wxDefaultSize,
+			sizeof(speeds) / sizeof(wxString),
+			speeds
+			);
+	myScsiSpeedCtrl->SetToolTip(_("Limit SCSI interface speed"));
+	fgs->Add(myScsiSpeedCtrl);
+
 	fgs->Add(new wxStaticText(this, wxID_ANY, _("Startup Delay (seconds)")));
 	myStartDelayCtrl =
 		new wxTextCtrl(
@@ -118,33 +138,6 @@ BoardPanel::BoardPanel(wxWindow* parent, const S2S_BoardCfg& initialConfig) :
 	myScsi2Ctrl->SetToolTip(_("Enable high-performance mode. May cause problems with SASI/SCSI1 hosts."));
 	fgs->Add(myScsi2Ctrl);
 
-	fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
-	myGlitchCtrl =
-		new wxCheckBox(
-			this,
-			ID_glitchCtrl,
-			_("Disable glitch filter"));
-	myGlitchCtrl->SetToolTip(_("Improve performance at the cost of noise immunity. Only use with short cables."));
-	fgs->Add(myGlitchCtrl);
-
-	fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
-	myCacheCtrl =
-		new wxCheckBox(
-			this,
-			ID_cacheCtrl,
-			_("Enable disk cache (experimental)"));
-	myCacheCtrl->SetToolTip(_("SD IO commands aren't completed when SCSI commands complete"));
-	fgs->Add(myCacheCtrl);
-
-	fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
-	myDisconnectCtrl =
-		new wxCheckBox(
-			this,
-			ID_disconnectCtrl,
-			_("Enable SCSI Disconnect"));
-	myDisconnectCtrl->SetToolTip(_("Release the SCSI bus while waiting for SD card writes to complete. Must also be enabled in host OS."));
-	fgs->Add(myDisconnectCtrl);
-
 	fgs->Add(new wxStaticText(this, wxID_ANY, wxT("")));
 	mySelLatchCtrl =
 		new wxCheckBox(
@@ -185,9 +178,6 @@ BoardPanel::getConfig() const
 		(myParityCtrl->IsChecked() ? S2S_CFG_ENABLE_PARITY : 0) |
 		(myUnitAttCtrl->IsChecked() ? S2S_CFG_ENABLE_UNIT_ATTENTION : 0) |
 		(myScsi2Ctrl->IsChecked() ? S2S_CFG_ENABLE_SCSI2 : 0) |
-		(myGlitchCtrl->IsChecked() ? S2S_CFG_DISABLE_GLITCH : 0) |
-		(myCacheCtrl->IsChecked() ? S2S_CFG_ENABLE_CACHE: 0) |
-		(myDisconnectCtrl->IsChecked() ? S2S_CFG_ENABLE_DISCONNECT: 0) |
 		(mySelLatchCtrl->IsChecked() ? S2S_CFG_ENABLE_SEL_LATCH : 0) |
 		(myMapLunsCtrl->IsChecked() ? S2S_CFG_MAP_LUNS_TO_IDS : 0);
 
@@ -195,6 +185,7 @@ BoardPanel::getConfig() const
 
 	config.startupDelay = CtrlGetValue<unsigned int>(myStartDelayCtrl).first;
 	config.selectionDelay = CtrlGetValue<unsigned int>(mySelDelayCtrl).first;
+	config.scsiSpeed = myScsiSpeedCtrl->GetSelection();
 	return config;
 }
 
@@ -206,10 +197,7 @@ BoardPanel::setConfig(const S2S_BoardCfg& config)
 	myParityCtrl->SetValue(config.flags & S2S_CFG_ENABLE_PARITY);
 	myUnitAttCtrl->SetValue(config.flags & S2S_CFG_ENABLE_UNIT_ATTENTION);
 	myScsi2Ctrl->SetValue(config.flags & S2S_CFG_ENABLE_SCSI2);
-	myGlitchCtrl->SetValue(config.flags & S2S_CFG_DISABLE_GLITCH);
 	myTermCtrl->SetValue(config.flags6 & S2S_CFG_ENABLE_TERMINATOR);
-	myCacheCtrl->SetValue(config.flags & S2S_CFG_ENABLE_CACHE);
-	myDisconnectCtrl->SetValue(config.flags & S2S_CFG_ENABLE_DISCONNECT);
 	mySelLatchCtrl->SetValue(config.flags & S2S_CFG_ENABLE_SEL_LATCH);
 	myMapLunsCtrl->SetValue(config.flags & S2S_CFG_MAP_LUNS_TO_IDS);
 
@@ -223,6 +211,7 @@ BoardPanel::setConfig(const S2S_BoardCfg& config)
 		conv << static_cast<unsigned int>(config.selectionDelay);
 		mySelDelayCtrl->ChangeValue(conv.str());
 	}
+	myScsiSpeedCtrl->SetSelection(config.scsiSpeed);
 }
 
 

+ 4 - 7
lib/SCSI2SD/src/scsi2sd-util6/BoardPanel.hh

@@ -55,14 +55,12 @@ private:
 		ID_parityCtrl = wxID_HIGHEST + 1,
 		ID_unitAttCtrl,
 		ID_scsi2Ctrl,
-		ID_glitchCtrl,
 		ID_termCtrl,
-		ID_cacheCtrl,
-		ID_disconnectCtrl,
 		ID_selLatchCtrl,
 		ID_mapLunsCtrl,
 		ID_startDelayCtrl,
-		ID_selDelayCtrl
+		ID_selDelayCtrl,
+		ID_scsiSpeedCtrl
 	};
 
 	wxWindow* myParent;
@@ -72,16 +70,15 @@ private:
 	wxCheckBox* myParityCtrl;
 	wxCheckBox* myUnitAttCtrl;
 	wxCheckBox* myScsi2Ctrl;
-	wxCheckBox* myGlitchCtrl;
 	wxCheckBox* myTermCtrl;
-	wxCheckBox* myCacheCtrl;
-	wxCheckBox* myDisconnectCtrl;
 	wxCheckBox* mySelLatchCtrl;
 	wxCheckBox* myMapLunsCtrl;
 
 	wxIntegerValidator<uint8_t>* myDelayValidator;
 	wxTextCtrl* myStartDelayCtrl;
 	wxTextCtrl* mySelDelayCtrl;
+
+	wxChoice* myScsiSpeedCtrl;
 };
 
 } // namespace SCSI2SD

+ 57 - 60
lib/SCSI2SD/src/scsi2sd-util6/ConfigUtil.cc

@@ -213,9 +213,19 @@ ConfigUtil::toXML(const S2S_TargetCfg& config)
 		"	<!-- ********************************************************\n" <<
 		"	Space separated list. Available options:\n" <<
 		"	apple\t\tReturns Apple-specific mode pages\n" <<
+		"	omti\t\tOMTI host non-standard link control\n" <<
 		"	********************************************************* -->\n" <<
-		"	<quirks>" <<
-			(config.quirks & S2S_CFG_QUIRKS_APPLE ? "apple" : "") <<
+		"	<quirks>";
+	if (config.quirks == S2S_CFG_QUIRKS_APPLE)
+	{
+		s << "apple";
+	}
+	else if (config.quirks == S2S_CFG_QUIRKS_OMTI)
+	{
+		s << "omti";
+	}
+
+	s <<
 			"</quirks>\n" <<
 
 		"\n\n" <<
@@ -315,26 +325,6 @@ ConfigUtil::toXML(const S2S_BoardCfg& config)
 			(config.flags & S2S_CFG_ENABLE_SCSI2 ? "true" : "false") <<
 			"</enableScsi2>\n" <<
 
-		"	<enableCache>" <<
-			(config.flags & S2S_CFG_ENABLE_CACHE ? "true" : "false") <<
-			"</enableCache>\n" <<
-
-		"	<!-- ********************************************************\n" <<
-		"	Setting to 'true' will result in increased performance at the\n" <<
-		"	cost of lower noise immunity.\n" <<
-		"	Only set to true when using short cables with only 1 or two\n" <<
-		"	devices. This should remain off when using external SCSI1 DB25\n" <<
-		"	cables.\n" <<
-		"	********************************************************* -->\n" <<
-		"	<disableGlitchFilter>" <<
-			(config.flags & S2S_CFG_DISABLE_GLITCH ? "true" : "false") <<
-			"</disableGlitchFilter>\n" <<
-
-
-		"	<enableDisconnect>" <<
-			(config.flags & S2S_CFG_ENABLE_DISCONNECT ? "true" : "false") <<
-			"</enableDisconnect>\n" <<
-
 		"	<!-- ********************************************************\n" <<
 		"	Respond to very short duration selection attempts. This supports\n" <<
 		"	non-standard hardware, but is generally safe to enable.\n" <<
@@ -356,6 +346,34 @@ ConfigUtil::toXML(const S2S_BoardCfg& config)
 		"	<mapLunsToIds>" <<
 			(config.flags & S2S_CFG_MAP_LUNS_TO_IDS ? "true" : "false") <<
 			"</mapLunsToIds>\n" <<
+
+
+		"	<!-- ********************************************************\n" <<
+		"	Delay (in milliseconds) before responding to a SCSI selection.\n" <<
+		"	255 (auto) sets it to 0 for SCSI2 hosts and 1ms otherwise.\n" <<
+		"	Some samplers need this set to 1 manually.\n" <<
+		"	********************************************************* -->\n" <<
+		"	<selectionDelay>" << static_cast<int>(config.selectionDelay) << "</selectionDelay>\n" <<
+
+		"	<!-- ********************************************************\n" <<
+		"	Startup delay (in seconds) before responding to the SCSI bus \n" <<
+		"	after power on. Default = 0.\n" <<
+		"	********************************************************* -->\n" <<
+		"	<startupDelay>" << static_cast<int>(config.startupDelay) << "</startupDelay>\n" <<
+
+		"	<!-- ********************************************************\n" <<
+		"	Speed limit the SCSI interface. This is the -max- speed the \n" <<
+		"	device will run at. The actual spee depends on the capability\n" <<
+		"	of the host controller.\n" <<
+		"	0	No limit\n" <<
+		"	1	Async 1.5MB/s\n" <<
+		"	2	Async 3.3MB/s\n" <<
+		"	3	Async 5MB/s\n" <<
+		"	4	Sync 5MB/s\n" <<
+		"	5	Sync 10MB/s\n" <<
+		"	********************************************************* -->\n" <<
+		"	<scsiSpeed>" << static_cast<int>(config.scsiSpeed) << "</scsiSpeed>\n" <<
+
 		"</S2S_BoardCfg>\n";
 
 	return s.str();
@@ -434,6 +452,10 @@ parseTarget(wxXmlNode* node)
 				{
 					result.quirks |= S2S_CFG_QUIRKS_APPLE;
 				}
+				else if (quirk == "omti")
+				{
+					result.quirks |= S2S_CFG_QUIRKS_OMTI;
+				}
 			}
 		}
 		else if (child->GetName() == "deviceType")
@@ -507,8 +529,15 @@ parseBoardConfig(wxXmlNode* node)
 	wxXmlNode *child = node->GetChildren();
 	while (child)
 	{
-// FIXME WHERE IS SELECTION DELAY ? STARTUP DELAY ? FFS.
-		if (child->GetName() == "unitAttention")
+		if (child->GetName() == "selectionDelay")
+		{
+			result.selectionDelay = parseInt(child, 255);
+		}
+		else if (child->GetName() == "startupDelay")
+		{
+			result.startupDelay = parseInt(child, 255);
+		}
+		else if (child->GetName() == "unitAttention")
 		{
 			std::string s(child->GetNodeContent().mb_str());
 			if (s == "true")
@@ -544,18 +573,6 @@ parseBoardConfig(wxXmlNode* node)
 				result.flags = result.flags & ~S2S_CFG_ENABLE_SCSI2;
 			}
 		}
-		else if (child->GetName() == "disableGlitchFilter")
-		{
-			std::string s(child->GetNodeContent().mb_str());
-			if (s == "true")
-			{
-				result.flags |= S2S_CFG_DISABLE_GLITCH;
-			}
-			else
-			{
-				result.flags = result.flags & ~S2S_CFG_DISABLE_GLITCH;
-			}
-		}
 		else if (child->GetName() == "enableTerminator")
 		{
 			std::string s(child->GetNodeContent().mb_str());
@@ -568,30 +585,6 @@ parseBoardConfig(wxXmlNode* node)
 				result.flags6 = result.flags & ~S2S_CFG_ENABLE_TERMINATOR;
 			}
 		}
-		else if (child->GetName() == "enableCache")
-		{
-			std::string s(child->GetNodeContent().mb_str());
-			if (s == "true")
-			{
-				result.flags |= S2S_CFG_ENABLE_CACHE;
-			}
-			else
-			{
-				result.flags = result.flags & ~S2S_CFG_ENABLE_CACHE;
-			}
-		}
-		else if (child->GetName() == "enableDisconnect")
-		{
-			std::string s(child->GetNodeContent().mb_str());
-			if (s == "true")
-			{
-				result.flags |= S2S_CFG_ENABLE_DISCONNECT;
-			}
-			else
-			{
-				result.flags = result.flags & ~S2S_CFG_ENABLE_DISCONNECT;
-			}
-		}
 		else if (child->GetName() == "selLatch")
 		{
 			std::string s(child->GetNodeContent().mb_str());
@@ -616,6 +609,10 @@ parseBoardConfig(wxXmlNode* node)
 				result.flags = result.flags & ~S2S_CFG_MAP_LUNS_TO_IDS;
 			}
 		}
+		else if (child->GetName() == "scsiSpeed")
+		{
+			result.scsiSpeed = parseInt(child, S2S_CFG_SPEED_SYNC_10);
+		}
 		child = child->GetNext();
 	}
 	return result;

+ 5 - 3
lib/SCSI2SD/src/scsi2sd-util6/Makefile

@@ -49,8 +49,8 @@ CPPFLAGS = $(CPPFLAGS_HIDAPI) -I. -I ../../include -ITerminalWx/src \
 	-DHAVE_LIBUSB_1_0 \
 
 
-CFLAGS += -Wall -Wno-pointer-sign -O2 -g
-CXXFLAGS += -Wall -O2 -g -std=c++0x
+CFLAGS += -Wall -Wno-pointer-sign -O2 -g -fPIC
+CXXFLAGS += -Wall -O2 -g -std=c++0x -fPIC
 
 LDFLAGS += -L$(BUILD)/libzipper/.libs -lzipper \
 	$(LDFLAGS_ZLIB) \
@@ -60,7 +60,8 @@ LDFLAGS += -L$(BUILD)/libzipper/.libs -lzipper \
 
 # wxWidgets 3.0.2 uses broken Webkit headers under OSX Yosemeti
 # liblzma not available on OSX 10.7
-WX_CONFIG=--disable-webkit --disable-webviewwebkit  \
+# --disable-mediactrl for missing Quicktime.h on Mac OSX Sierra
+WX_CONFIG=--disable-webkit --disable-webviewwebkit  --disable-mediactrl \
 	--without-libtiff --without-libjbig --without-liblzma --without-opengl \
 	--enable-monolithic --enable-stl --disable-shared
 
@@ -110,6 +111,7 @@ ifeq ($(TARGET),Darwin)
 all: $(BUILD)/scsi2sd-util6.dmg
 
 $(BUILD)/scsi2sd-util6.dmg: $(BUILD)/scsi2sd-util6 $(BUILD)/dfu-util/buildstamp
+	rm -rf $(dir $@)/dmg $@
 	mkdir -p $(dir $@)/dmg
 	cp $(BUILD)/scsi2sd-util6 $(BUILD)/dfu-util/src/dfu-util $(dir $@)/dmg
 	chmod a+rx $(dir $@)/dmg/*

+ 2 - 2
lib/SCSI2SD/src/scsi2sd-util6/TargetPanel.cc

@@ -311,8 +311,8 @@ TargetPanel::evaluate()
 	switch (myDeviceTypeCtrl->GetSelection())
 	{
 	case S2S_CFG_OPTICAL:
-		// TODO mySectorSizeCtrl->ChangeValue("2048");
-		// TODO mySectorSizeCtrl->Enable(false);
+		mySectorSizeCtrl->ChangeValue("2048");
+		mySectorSizeCtrl->Enable(true); // Enable override
 		break;
 	case S2S_CFG_FLOPPY_14MB:
 		mySectorSizeCtrl->ChangeValue("512");

+ 17 - 18
lib/SCSI2SD/src/scsi2sd-util6/scsi2sd-util.cc

@@ -160,6 +160,18 @@ public:
 			ID_ConfigDefaults,
 			_("Load &Defaults"),
 			_("Load default configuration options."));
+
+		menuFile->AppendSeparator();
+		myLoadButton = menuFile->Append(
+			ID_BtnLoad,
+			_("Load from device"),
+			_("Load configuration from hardware device"));
+		mySaveButton = menuFile->Append(
+			ID_BtnSave,
+			_("Save to device"),
+			_("Save configuration to hardware device"));
+
+		menuFile->AppendSeparator();
 		menuFile->Append(
 			ID_Firmware,
 			_("&Upgrade Firmware..."),
@@ -219,19 +231,6 @@ public:
 			tabs->Fit();
 			fgs->Add(tabs);
 
-
-			wxPanel* btnPanel = new wxPanel(cfgPanel);
-			wxFlexGridSizer *btnFgs = new wxFlexGridSizer(1, 2, 5, 5);
-			btnPanel->SetSizer(btnFgs);
-			myLoadButton =
-				new wxButton(btnPanel, ID_BtnLoad, _("Load from device"));
-			btnFgs->Add(myLoadButton);
-			mySaveButton =
-				new wxButton(btnPanel, ID_BtnSave, _("Save to device"));
-			btnFgs->Add(mySaveButton);
-			fgs->Add(btnPanel);
-
-			btnPanel->Fit();
 			cfgPanel->Fit();
 		}
 
@@ -253,10 +252,10 @@ private:
 	wxLogWindow* myLogWindow;
 	BoardPanel* myBoardPanel;
 	std::vector<TargetPanel*> myTargets;
-	wxButton* myLoadButton;
-	wxButton* mySaveButton;
 	wxMenuItem* mySCSILogChk;
 	wxMenuItem* mySelfTestChk;
+	wxMenuItem* myLoadButton;
+	wxMenuItem* mySaveButton;
 	wxTimer* myTimer;
 	shared_ptr<HID> myHID;
 	bool myInitialConfig;
@@ -945,7 +944,7 @@ private:
 	{
 		wxMessageBox(
 			"SCSI2SD (scsi2sd-util6)\n"
-			"Copyright (C) 2014-2016 Michael McMaster <michael@codesrc.com>\n"
+			"Copyright (C) 2014-2017 Michael McMaster <michael@codesrc.com>\n"
 			"\n"
 "This program is free software: you can redistribute it and/or modify\n"
 "it under the terms of the GNU General Public License as published by\n"
@@ -979,8 +978,8 @@ wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
 
 	EVT_COMMAND(wxID_ANY, ConfigChangedEvent, AppFrame::onConfigChanged)
 
-	EVT_BUTTON(ID_BtnSave, AppFrame::doSave)
-	EVT_BUTTON(ID_BtnLoad, AppFrame::doLoad)
+	EVT_MENU(ID_BtnSave, AppFrame::doSave)
+	EVT_MENU(ID_BtnLoad, AppFrame::doLoad)
 
 	EVT_CLOSE(AppFrame::OnCloseEvt)
 

+ 1 - 1
lib/SCSI2SD/src/scsi2sd-util6/wxWidgets/src/osx/carbon/dataobj.cpp

@@ -30,7 +30,7 @@
 #include "wx/osx/private.h"
 
 #if wxOSX_USE_COCOA_OR_CARBON
-    #include <QuickTime/QuickTime.h>
+//    #include <QuickTime/QuickTime.h>
 #endif
 
 // ----------------------------------------------------------------------------

+ 1 - 1
lib/SCSI2SD/src/scsi2sd-util6/wxWidgets/src/osx/core/bitmap.cpp

@@ -36,7 +36,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
 #endif
 
 #ifndef __WXOSX_IPHONE__
-#include <QuickTime/QuickTime.h>
+//#include <QuickTime/QuickTime.h>
 #endif
 
 CGColorSpaceRef wxMacGetGenericRGBColorSpace();