SCSI2SD/software/scsi2sd-util/SCSI2SD_Bootloader.cc
2020-10-12 13:06:02 +10:00

258 lines
4.9 KiB
C++

// Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
//
// This file is part of SCSI2SD.
//
// SCSI2SD is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// SCSI2SD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
#include "SCSI2SD_Bootloader.hh"
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string.h>
using namespace SCSI2SD;
hid_device* SCSI2SDHID_handle = NULL;
// cybtldr interface.
extern "C" int
SCSI2SDHID_OpenConnection(void)
{
return 0;
}
extern "C" int
SCSI2SDHID_CloseConnection(void)
{
return 0;
}
extern "C" int
SCSI2SDHID_ReadData(unsigned char* data, int count)
{
uint8_t buf[65];
buf[0] = 0; // Report ID
int result = hid_read(SCSI2SDHID_handle, buf, count);
if (result < 0)
{
std::cerr << "USB HID Read Failure: " <<
hid_error(SCSI2SDHID_handle) << std::endl;
}
memcpy(data, buf, count);
return (result >= 0) ? 0 : -1;
}
extern "C" int
SCSI2SDHID_WriteData(unsigned char* data, int count)
{
uint8_t buf[65];
buf[0] = 0; // report ID
int i;
for (i = 0; i < count; ++i)
{
buf[i+1] = data[i];
}
int result = -1;
for (int retry = 0; retry < 3 && result < 0; ++retry)
{
result = hid_write(SCSI2SDHID_handle, buf, count + 1);
}
if (result < 0)
{
std::cerr << "USB HID Write Failure: " <<
hid_error(SCSI2SDHID_handle) << std::endl;
}
return (result >= 0) ? 0 : -1;
}
static CyBtldr_CommunicationsData g_cyComms =
{
&SCSI2SDHID_OpenConnection,
&SCSI2SDHID_CloseConnection,
&SCSI2SDHID_ReadData,
&SCSI2SDHID_WriteData,
Bootloader::HID_PACKET_SIZE
};
Bootloader::OperationScope::OperationScope()
{
unsigned long blVer;
if (CyBtldr_StartBootloadOperation(&g_cyComms, 0x2e133069, 0, &blVer)
!= CYRET_SUCCESS)
{
throw std::runtime_error("Could not start bootloader operation");
}
}
Bootloader::OperationScope::~OperationScope()
{
CyBtldr_EndBootloadOperation();
}
Bootloader::Bootloader(hid_device_info* hidInfo) :
myHidInfo(hidInfo),
myBootloaderHandle(NULL)
{
myBootloaderHandle = hid_open_path(hidInfo->path);
if (!myBootloaderHandle)
{
std::stringstream msg;
msg << "Error opening HID device " << hidInfo->path << std::endl;
hid_free_enumeration(myHidInfo);
myHidInfo = NULL;
throw std::runtime_error(msg.str());
}
else
{
SCSI2SDHID_handle = myBootloaderHandle;
}
}
Bootloader::~Bootloader()
{
if (myBootloaderHandle)
{
hid_close(myBootloaderHandle);
}
SCSI2SDHID_handle = NULL;
hid_free_enumeration(myHidInfo);
}
Bootloader*
Bootloader::Open()
{
hid_device_info* dev = hid_enumerate(VENDOR_ID, PRODUCT_ID);
if (dev)
{
return new Bootloader(dev);
}
else
{
return NULL;
}
}
Bootloader::HWInfo
Bootloader::getHWInfo() const
{
HWInfo info = {"unknown", "unknown", "unknown"};
switch (myHidInfo->release_number)
{
case 0x3001:
info.desc = "3.5\" SCSI2SD (green)";
info.version = "V3.0";
info.firmwareName = "SCSI2SD-V3.cyacd";
break;
case 0x3002:
info.desc = "3.5\" SCSI2SD (yellow/red) or 2.5\" SCSI2SD for Apple Powerbook";
info.version = "V4.1/V4.2/V5.0";
info.firmwareName = "SCSI2SD-V4.cyacd";
break;
case 0x3003:
info.desc = "3.5\" SCSI2SD";
info.version = "V5.1";
info.firmwareName = "SCSI2SD-V51.cyacd";
case 0x3004:
info.desc = "3.5\" SCSI2SD";
info.version = "V5.2";
info.firmwareName = "SCSI2SD-V52.cyacd";
break;
case 0x0055:
info.desc = "External DB25 SCSI2SD";
info.version = "V5.5";
info.firmwareName = "SCSI2SD-V55.cyacd";
break;
}
return info;
}
bool
Bootloader::isCorrectFirmware(const std::string& path) const
{
HWInfo info = getHWInfo();
return path.rfind(info.firmwareName) != std::string::npos;
}
std::string
Bootloader::getDevicePath() const
{
return myHidInfo->path;
}
std::wstring
Bootloader::getManufacturer() const
{
return myHidInfo->manufacturer_string;
}
std::wstring
Bootloader::getProductString() const
{
return myHidInfo->product_string;
}
void
Bootloader::load(const std::string& path, void (*progress)(uint8_t, uint16_t))
{
int result = CyBtldr_Program(
path.c_str(),
&g_cyComms,
progress);
if (result)
{
throw std::runtime_error("Firmware update failed");
}
}
bool
Bootloader::ping() const
{
try
{
Bootloader::OperationScope operationGuard;
int result = CyBtldr_VerifyRow(0, 0, 0);
switch (result)
{
case CYRET_SUCCESS:
case CYRET_ERR_CHECKSUM: // We supplied a dummy value of 0.
return true;
default: return false;
}
}
catch (std::exception& e)
{
return false;
}
}