From af675dcf208049dd11692a0f22645342e00dcf08 Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Wed, 29 Mar 2017 19:51:47 +1000 Subject: [PATCH] Lots of bug fixing, and 4.7 merges --- CHANGELOG | 5 +- Makefile | 1 + include/scsi2sd.h | 17 ++- rtl/fpga_bitmap.o | Bin 32724 -> 32724 bytes src/firmware/config.c | 6 +- src/firmware/disk.c | 2 + src/firmware/scsi.c | 44 +++++- src/firmware/scsiPhy.c | 143 ++++++++++++------ src/firmware/scsiPhy.h | 11 +- src/firmware/time.h | 2 +- src/scsi2sd-util6/BoardPanel.cc | 57 +++---- src/scsi2sd-util6/BoardPanel.hh | 11 +- src/scsi2sd-util6/ConfigUtil.cc | 117 +++++++------- src/scsi2sd-util6/Makefile | 8 +- src/scsi2sd-util6/TargetPanel.cc | 4 +- src/scsi2sd-util6/scsi2sd-util.cc | 35 +++-- .../wxWidgets/src/osx/carbon/dataobj.cpp | 2 +- .../wxWidgets/src/osx/core/bitmap.cpp | 2 +- 18 files changed, 275 insertions(+), 192 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c0579e09..3c17ec20 100644 --- a/CHANGELOG +++ b/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 diff --git a/Makefile b/Makefile index b90b51a3..b6a296d8 100644 --- a/Makefile +++ b/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) diff --git a/include/scsi2sd.h b/include/scsi2sd.h index e15d0b09..6048e55f 100755 --- a/include/scsi2sd.h +++ b/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 diff --git a/rtl/fpga_bitmap.o b/rtl/fpga_bitmap.o index 6cbce7c58ef6b593e699f40565e37b8c6806855b..c7f26cf18d87115c81f093ca4db32b9547ff81bf 100644 GIT binary patch literal 32724 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 UA^cJ0(ehfrcM51Z$jSTv0Pyct-T(jq literal 32724 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 diff --git a/src/firmware/config.c b/src/firmware/config.c index 9bb8b113..edb4be06 100755 --- a/src/firmware/config.c +++ b/src/firmware/config.c @@ -38,7 +38,7 @@ #include -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)); } diff --git a/src/firmware/disk.c b/src/firmware/disk.c index d234854e..4496c289 100755 --- a/src/firmware/disk.c +++ b/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 diff --git a/src/firmware/scsi.c b/src/firmware/scsi.c index 0b9b8078..854707d5 100755 --- a/src/firmware/scsi.c +++ b/src/firmware/scsi.c @@ -29,6 +29,7 @@ //#include "debug.h" #include "tape.h" #include "mo.h" +#include "vendor.h" #include @@ -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; } } diff --git a/src/firmware/scsiPhy.c b/src/firmware/scsiPhy.c index fe92d247..c0f8cdb0 100755 --- a/src/firmware/scsiPhy.c +++ b/src/firmware/scsiPhy.c @@ -28,45 +28,53 @@ #include -// 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; } diff --git a/src/firmware/scsiPhy.h b/src/firmware/scsiPhy.h index c16d9314..f8f5bdda 100755 --- a/src/firmware/scsiPhy.h +++ b/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) diff --git a/src/firmware/time.h b/src/firmware/time.h index 4970f589..1926b2ee 100755 --- a/src/firmware/time.h +++ b/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); diff --git a/src/scsi2sd-util6/BoardPanel.cc b/src/scsi2sd-util6/BoardPanel.cc index 54ea2352..157435b1 100644 --- a/src/scsi2sd-util6/BoardPanel.cc +++ b/src/scsi2sd-util6/BoardPanel.cc @@ -53,7 +53,7 @@ BoardPanel::BoardPanel(wxWindow* parent, const S2S_BoardCfg& initialConfig) : myParent(parent), myDelayValidator(new wxIntegerValidator) { - 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(myStartDelayCtrl).first; config.selectionDelay = CtrlGetValue(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(config.selectionDelay); mySelDelayCtrl->ChangeValue(conv.str()); } + myScsiSpeedCtrl->SetSelection(config.scsiSpeed); } diff --git a/src/scsi2sd-util6/BoardPanel.hh b/src/scsi2sd-util6/BoardPanel.hh index 8a8bc04f..9d419b77 100644 --- a/src/scsi2sd-util6/BoardPanel.hh +++ b/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* myDelayValidator; wxTextCtrl* myStartDelayCtrl; wxTextCtrl* mySelDelayCtrl; + + wxChoice* myScsiSpeedCtrl; }; } // namespace SCSI2SD diff --git a/src/scsi2sd-util6/ConfigUtil.cc b/src/scsi2sd-util6/ConfigUtil.cc index 9db2ded6..42362290 100755 --- a/src/scsi2sd-util6/ConfigUtil.cc +++ b/src/scsi2sd-util6/ConfigUtil.cc @@ -213,9 +213,19 @@ ConfigUtil::toXML(const S2S_TargetCfg& config) " \n" << - " " << - (config.quirks & S2S_CFG_QUIRKS_APPLE ? "apple" : "") << + " "; + if (config.quirks == S2S_CFG_QUIRKS_APPLE) + { + s << "apple"; + } + else if (config.quirks == S2S_CFG_QUIRKS_OMTI) + { + s << "omti"; + } + + s << "\n" << "\n\n" << @@ -315,26 +325,6 @@ ConfigUtil::toXML(const S2S_BoardCfg& config) (config.flags & S2S_CFG_ENABLE_SCSI2 ? "true" : "false") << "\n" << - " " << - (config.flags & S2S_CFG_ENABLE_CACHE ? "true" : "false") << - "\n" << - - " \n" << - " " << - (config.flags & S2S_CFG_DISABLE_GLITCH ? "true" : "false") << - "\n" << - - - " " << - (config.flags & S2S_CFG_ENABLE_DISCONNECT ? "true" : "false") << - "\n" << - " \n" << + " " << static_cast(config.selectionDelay) << "\n" << + + " \n" << + " " << static_cast(config.startupDelay) << "\n" << + + " \n" << + " " << static_cast(config.scsiSpeed) << "\n" << + "\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; diff --git a/src/scsi2sd-util6/Makefile b/src/scsi2sd-util6/Makefile index 28a10367..42e1d9b6 100755 --- a/src/scsi2sd-util6/Makefile +++ b/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/* diff --git a/src/scsi2sd-util6/TargetPanel.cc b/src/scsi2sd-util6/TargetPanel.cc index 94c822bd..fb8b07d2 100755 --- a/src/scsi2sd-util6/TargetPanel.cc +++ b/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"); diff --git a/src/scsi2sd-util6/scsi2sd-util.cc b/src/scsi2sd-util6/scsi2sd-util.cc index 988f9c7b..ebdc8f74 100644 --- a/src/scsi2sd-util6/scsi2sd-util.cc +++ b/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 myTargets; - wxButton* myLoadButton; - wxButton* mySaveButton; wxMenuItem* mySCSILogChk; wxMenuItem* mySelfTestChk; + wxMenuItem* myLoadButton; + wxMenuItem* mySaveButton; wxTimer* myTimer; shared_ptr myHID; bool myInitialConfig; @@ -945,7 +944,7 @@ private: { wxMessageBox( "SCSI2SD (scsi2sd-util6)\n" - "Copyright (C) 2014-2016 Michael McMaster \n" + "Copyright (C) 2014-2017 Michael McMaster \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) diff --git a/src/scsi2sd-util6/wxWidgets/src/osx/carbon/dataobj.cpp b/src/scsi2sd-util6/wxWidgets/src/osx/carbon/dataobj.cpp index 758e3a79..6757e5e9 100644 --- a/src/scsi2sd-util6/wxWidgets/src/osx/carbon/dataobj.cpp +++ b/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 +// #include #endif // ---------------------------------------------------------------------------- diff --git a/src/scsi2sd-util6/wxWidgets/src/osx/core/bitmap.cpp b/src/scsi2sd-util6/wxWidgets/src/osx/core/bitmap.cpp index 3c61c173..4dd8e8e3 100644 --- a/src/scsi2sd-util6/wxWidgets/src/osx/core/bitmap.cpp +++ b/src/scsi2sd-util6/wxWidgets/src/osx/core/bitmap.cpp @@ -36,7 +36,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) #endif #ifndef __WXOSX_IPHONE__ -#include +//#include #endif CGColorSpaceRef wxMacGetGenericRGBColorSpace(); -- 2.38.5