diff --git a/cpp/devices/device_factory.cpp b/cpp/devices/device_factory.cpp index 92449ac5..4617fa45 100644 --- a/cpp/devices/device_factory.cpp +++ b/cpp/devices/device_factory.cpp @@ -15,6 +15,7 @@ #include "scsi_printer.h" #include "scsi_host_bridge.h" #include "scsi_daynaport.h" +#include "scsi_powerview.h" #include "host_services.h" #include "device_factory.h" #include @@ -64,6 +65,7 @@ DeviceFactory::DeviceFactory() device_mapping["daynaport"] = SCDP; device_mapping["printer"] = SCLP; device_mapping["services"] = SCHS; + device_mapping["powerview"] = SCPV; } PbDeviceType DeviceFactory::GetTypeForFile(const string& filename) const @@ -151,6 +153,15 @@ shared_ptr DeviceFactory::CreateDevice(PbDeviceType type, int lun device->SetDefaultParams(default_params.find(SCLP)->second); break; + case SCPV: + device = make_shared(lun); + // Since this is an emulation for a specific device the full INQUIRY data have to be set accordingly + device->SetVendor("RADIUS "); + device->SetProduct("PowerView "); + device->SetRevision("V1.0"); + device->SetDefaultParams(default_params.find(SCPV)->second); + break; + default: break; } diff --git a/cpp/devices/interfaces/byte_writer.h b/cpp/devices/interfaces/byte_writer.h index bfbfa5ee..b88e7586 100644 --- a/cpp/devices/interfaces/byte_writer.h +++ b/cpp/devices/interfaces/byte_writer.h @@ -12,6 +12,7 @@ #pragma once #include +#include using namespace std; diff --git a/cpp/devices/scsi_powerview.cpp b/cpp/devices/scsi_powerview.cpp index cf3ca4da..7b2cdc3d 100644 --- a/cpp/devices/scsi_powerview.cpp +++ b/cpp/devices/scsi_powerview.cpp @@ -1,12 +1,11 @@ //--------------------------------------------------------------------------- // -// SCSI Target Emulator RaSCSI (*^..^*) -// for Raspberry Pi +// SCSI Target Emulator PiSCSI for Raspberry Pi // -// Copyright (C) 2020-2021 akuker +// Copyright (C) 2020-2023 akuker // Copyright (C) 2020 joshua stein // -// Licensed under the BSD 3-Clause License. +// Licensed under the BSD 3-Clause License. // See LICENSE file in the project root folder. // // [ Emulation of the Radius PowerView SCSI Display Adapter ] @@ -19,85 +18,99 @@ //--------------------------------------------------------------------------- #include "scsi_powerview.h" -#include #include +#include +#include +#include -#include "exceptions.h" +// #include "exceptions.h" #include #include #include -#include "os.h" -#include "disk.h" +// #include "os.h" +// #include "disk.h" #include -#include "log.h" -#include "controllers/scsidev_ctrl.h" + +#include "shared/log.h" +// #include "controllers/scsidev_ctrl.h" unsigned char SCSIPowerView::reverse_table[256]; -const BYTE SCSIPowerView::m_inquiry_response[] = { -0x03, 0x00, 0x01, 0x01, 0x46, 0x00, 0x00, 0x00, 0x52, 0x41, 0x44, 0x49, 0x55, 0x53, 0x20, 0x20, -0x50, 0x6F, 0x77, 0x65, 0x72, 0x56, 0x69, 0x65, 0x77, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -0x56, 0x31, 0x2E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, -0x05, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0xF9, 0x00, 0x00, 0xFF, +const uint8_t SCSIPowerView::m_inquiry_response[] = { + 0x03, 0x00, 0x01, 0x01, 0x46, 0x00, 0x00, 0x00, 0x52, 0x41, 0x44, 0x49, 0x55, 0x53, 0x20, 0x20, 0x50, 0x6F, 0x77, + 0x65, 0x72, 0x56, 0x69, 0x65, 0x77, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x56, 0x31, 0x2E, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0xF9, 0x00, 0x00, 0xFF, }; -SCSIPowerView::SCSIPowerView() : Disk("SCPV") +using namespace scsi_defs; +// using namespace scsi_command_util; + +SCSIPowerView::SCSIPowerView(int lun) : PrimaryDevice(SCPV, lun) { - LOGTRACE("Entering %s", __PRETTY_FUNCTION__); - AddCommand(SCSIDEV::eCmdPvReadConfig, "Unknown PowerViewC8", &SCSIPowerView::CmdReadConfig); - AddCommand(SCSIDEV::eCmdPvWriteConfig, "Unknown PowerViewC9", &SCSIPowerView::CmdWriteConfig); - AddCommand(SCSIDEV::eCmdPvWriteFrameBuffer, "Unknown PowerViewCA", &SCSIPowerView::CmdWriteFramebuffer); - AddCommand(SCSIDEV::eCmdPvWriteColorPalette, "Unknown PowerViewCB", &SCSIPowerView::CmdWriteColorPalette); - AddCommand(SCSIDEV::eCmdUnknownPowerViewCC, "Unknown PowerViewCC", &SCSIPowerView::UnknownCommandCC); - - LOGTRACE("%s - creating lookup table", __PRETTY_FUNCTION__); - - // create lookup table - for (int i = 0; i < 256; i++) { - unsigned char b = i; - b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; - b = (b & 0xCC) >> 2 | (b & 0x33) << 2; - b = (b & 0xAA) >> 1 | (b & 0x55) << 1; - reverse_table[i] = b; - } - - framebuffer_black = 0; - framebuffer_blue = (/*red*/ 0 << fbinfo.red.offset) | - (/*green*/ 0 << fbinfo.green.offset)| - (/*blue*/ 0xFF << fbinfo.blue.offset) | - (/*alpha*/ 0 << fbinfo.transp.offset); - framebuffer_yellow = (/*red*/ 0 << fbinfo.red.offset) | - (/*green*/ 0xFF << fbinfo.green.offset)| - (/*blue*/ 0x0 << fbinfo.blue.offset) | - (/*alpha*/ 0 << fbinfo.transp.offset); - framebuffer_red = (/*red*/ 0xFF << fbinfo.red.offset) | - (/*green*/ 0 << fbinfo.green.offset)| - (/*blue*/ 0 << fbinfo.blue.offset) | - (/*alpha*/ 0 << fbinfo.transp.offset); - - // Default to one bit color (black & white) if we don't know any better - color_depth = eColorsBW; - LOGTRACE("Done with %s", __PRETTY_FUNCTION__); + SupportsParams(true); } +bool SCSIPowerView::Init(const unordered_map& params) +{ + LOGTRACE("Entering %s", __PRETTY_FUNCTION__); + + PrimaryDevice::Init(params); + + // AddCommand(scsi_command::eCmdTestUnitReady, [this] { TestUnitReady(); }); + AddCommand(scsi_command::eCmdPvReadConfig, [this] { CmdReadConfig(); }); + AddCommand(scsi_command::eCmdPvWriteConfig, [this] { CmdWriteConfig(); }); + AddCommand(scsi_command::eCmdPvWriteFrameBuffer, [this] { CmdWriteFramebuffer(); }); + AddCommand(scsi_command::eCmdPvWriteColorPalette, [this] { CmdWriteColorPalette(); }); + AddCommand(scsi_command::eCmdUnknownPowerViewCC, [this] { UnknownCommandCC(); }); + + LOGTRACE("%s - creating lookup table", __PRETTY_FUNCTION__); + + // create lookup table + for (int i = 0; i < 256; i++) { + unsigned char b = i; + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + reverse_table[i] = b; + } + + framebuffer_black = 0; + framebuffer_blue = (/*red*/ 0 << fbinfo.red.offset) | (/*green*/ 0 << fbinfo.green.offset) | + (/*blue*/ 0xFF << fbinfo.blue.offset) | (/*alpha*/ 0 << fbinfo.transp.offset); + framebuffer_yellow = (/*red*/ 0 << fbinfo.red.offset) | (/*green*/ 0xFF << fbinfo.green.offset) | + (/*blue*/ 0x0 << fbinfo.blue.offset) | (/*alpha*/ 0 << fbinfo.transp.offset); + framebuffer_red = (/*red*/ 0xFF << fbinfo.red.offset) | (/*green*/ 0 << fbinfo.green.offset) | + (/*blue*/ 0 << fbinfo.blue.offset) | (/*alpha*/ 0 << fbinfo.transp.offset); + + // Default to one bit color (black & white) if we don't know any better + color_depth = eColorsBW; + + (void)HwInit(); + LOGTRACE("Done with %s", __PRETTY_FUNCTION__); + return true; +} + +// void SCSIPowerView::TestUnitReady() +// { +// // Always successful +// EnterStatusPhase(); +// } + //--------------------------------------------------------------------------- // // Log a message to the framebuffer display // //--------------------------------------------------------------------------- -void SCSIPowerView::fbcon_text(char* message) +void SCSIPowerView::fbcon_text(const char* message) { - int fd = open("/dev/tty1", O_RDWR); - if (0 < fd) - { - write(fd, message, strlen(message)); - } - else - { - LOGWARN("%s Unable to open /dev/tty1", __PRETTY_FUNCTION__); - } - close(fd); + int fd = open("/dev/tty1", O_RDWR); + if (0 < fd) { + write(fd, message, strlen(message)); + } else { + LOGWARN("%s Unable to open /dev/tty1", __PRETTY_FUNCTION__); + } + close(fd); } //--------------------------------------------------------------------------- @@ -108,17 +121,14 @@ void SCSIPowerView::fbcon_text(char* message) //--------------------------------------------------------------------------- void SCSIPowerView::fbcon_cursor(bool blank) { - int fd = open("/dev/tty1", O_RDWR); - if (0 < fd) - { - write(fd, "\033[?25", 5); - write(fd, blank ? "h" : "l", 1); - } - else - { - LOGWARN("%s Unable to open /dev/tty1", __PRETTY_FUNCTION__); - } - close(fd); + int fd = open("/dev/tty1", O_RDWR); + if (0 < fd) { + write(fd, "\033[?25", 5); + write(fd, blank ? "h" : "l", 1); + } else { + LOGWARN("%s Unable to open /dev/tty1", __PRETTY_FUNCTION__); + } + close(fd); } //--------------------------------------------------------------------------- @@ -129,50 +139,41 @@ void SCSIPowerView::fbcon_cursor(bool blank) //--------------------------------------------------------------------------- void SCSIPowerView::fbcon_blank(bool blank) { - int ret = ioctl(fbfd, FBIOBLANK, blank ? VESA_POWERDOWN : VESA_NO_BLANKING); - if(ret < 0){ - LOGWARN("%s Unable to disable blanking", __PRETTY_FUNCTION__); - } - return; + int ret = ioctl(fbfd, FBIOBLANK, blank ? VESA_POWERDOWN : VESA_NO_BLANKING); + if (ret < 0) { + LOGWARN("%s Unable to disable blanking", __PRETTY_FUNCTION__); + } + return; } SCSIPowerView::~SCSIPowerView() { - // Re-enable the cursor - fbcon_cursor(true); + // Re-enable the cursor + fbcon_cursor(true); - munmap(this->fb, fbfixinfo.smem_len); - close(this->fbfd); + munmap(this->fb, fbfixinfo.smem_len); + close(this->fbfd); - for (auto const& command : commands) { - delete command.second; - } + // for (auto const& command : commands) { + // delete command.second; + // } } -void SCSIPowerView::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (SCSIPowerView::*execute)(SASIDEV *)) +void SCSIPowerView::ClearFrameBuffer(uint32_t blank_color) { - commands[opcode] = new command_t(name, execute); -} - - -void SCSIPowerView::ClearFrameBuffer(DWORD blank_color){ - - // For each row - for (DWORD idx_row_y = 0; idx_row_y < fbinfo.yres-1; idx_row_y++){ - - // For each column - for (DWORD idx_col_x = 0; idx_col_x < fbinfo.xres-1; idx_col_x++){ - uint32_t loc = ((idx_col_x) * (this->fbbpp / 8)) + ((idx_row_y) * fblinelen); - uint8_t temp_color = blank_color; - - for(uint32_t i=0; i < fbinfo.bits_per_pixel/8; i++){ - temp_color = (blank_color >> 8*i) & 0xFF; - *(this->fb + loc + i) = temp_color; - } - } - } - + // For each row + for (uint32_t idx_row_y = 0; idx_row_y < fbinfo.yres - 1; idx_row_y++) { + // For each column + for (uint32_t idx_col_x = 0; idx_col_x < fbinfo.xres - 1; idx_col_x++) { + uint32_t loc = ((idx_col_x) * (this->fbbpp / 8)) + ((idx_row_y)*fblinelen); + uint8_t temp_color = blank_color; + for (uint32_t i = 0; i < fbinfo.bits_per_pixel / 8; i++) { + temp_color = (blank_color >> 8 * i) & 0xFF; + *(this->fb + loc + i) = temp_color; + } + } + } } //--------------------------------------------------------------------------- @@ -181,254 +182,310 @@ void SCSIPowerView::ClearFrameBuffer(DWORD blank_color){ // //--------------------------------------------------------------------------- // void SCSIPowerView::CmdPvReadConfig(SASIDEV *controller) -void SCSIPowerView::CmdReadConfig(SASIDEV *controller) +void SCSIPowerView::CmdReadConfig() { + // GetController()->SetLength(Read(GetController()->GetCmd(), GetController()->GetBuffer(), record)); + // GetController()->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN); + // GetController()->SetStatus(status::GOOD); + // GetController()->SetLength(RetrieveStats(GetController()->GetCmd(), GetController()->GetBuffer())); - // Set transfer amount - ctrl->length = ctrl->cmd[6]; - LOGWARN("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); + // // Set next block + // GetController()->SetBlocks(1); + // GetController()->SetNext(1); - if (ctrl->length <= 0) { - // Failure (Error) - controller->Error(); - return; - } + // Set transfer amount + /////// ctrl->length = ctrl->cmd[6]; + int length = GetController()->GetCmd(6); - // Response to "C8 00 00 31 83 00 01 00" is "00" - if(ctrl->cmd[4] == 0x83){ + GetController()->SetLength(length); + LOGWARN("%s Message Length %d", __PRETTY_FUNCTION__, (int)length); - if(ctrl->length != 1){ - LOGWARN("%s Received unexpected length: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, ctrl->cmd[0], ctrl->cmd[1], ctrl->cmd[2], ctrl->cmd[3], ctrl->cmd[4], ctrl->cmd[5]); - } - } - // Response to "C8 00 00 31 00 00 03 00" is "01 09 08" - else if(ctrl->cmd[4] == 0x00){ - if(ctrl->length != 3){ - LOGWARN("%s Received unexpected length: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, ctrl->cmd[0], ctrl->cmd[1], ctrl->cmd[2], ctrl->cmd[3], ctrl->cmd[4], ctrl->cmd[5]); - } - } - // Response to "C8 00 00 31 82 00 01 00" is "01" - else if(ctrl->cmd[4] == 0x82){ - ctrl->buffer[0] = 0x01; - if(ctrl->length != 1){ - LOGWARN("%s Received unexpected length: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, ctrl->cmd[0], ctrl->cmd[1], ctrl->cmd[2], ctrl->cmd[3], ctrl->cmd[4], ctrl->cmd[5]); - } - } - else{ - LOGWARN("%s Unhandled command received: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, ctrl->cmd[0], ctrl->cmd[1], ctrl->cmd[2], ctrl->cmd[3], ctrl->cmd[4], ctrl->cmd[5]); - ctrl->buffer[0] = 0x00; - ctrl->buffer[1] = 0x00; - ctrl->buffer[2] = 0x00; - } + vector& buffer = GetController()->GetBuffer(); - // Set next block - ctrl->blocks = 1; - ctrl->next = 1; + /////////if (ctrl->length <= 0) { + if (length <= 0) { + // Failure (Error) + ///////////controller->Error(); + GetController()->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); + return; + } - controller->DataIn(); + // Response to "C8 00 00 31 83 00 01 00" is "00" + //////////if(ctrl->cmd[4] == 0x83){ + if (GetController()->GetCmd(4) == 0x83) { + if (length != 1) { + LOGWARN("%s Received unexpected length: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, + GetController()->GetCmd(0), GetController()->GetCmd(1), GetController()->GetCmd(2), + GetController()->GetCmd(3), GetController()->GetCmd(4), GetController()->GetCmd(5)); + } + } + // Response to "C8 00 00 31 00 00 03 00" is "01 09 08" + /////////else if(ctrl->cmd[4] == 0x00){ + else if (GetController()->GetCmd(4) == 0x00) { + if (length != 3) { + LOGWARN("%s Received unexpected length: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, + GetController()->GetCmd(0), GetController()->GetCmd(1), GetController()->GetCmd(2), + GetController()->GetCmd(3), GetController()->GetCmd(4), GetController()->GetCmd(5)); + } + } + // Response to "C8 00 00 31 82 00 01 00" is "01" + else if (GetController()->GetCmd(4) == 0x82) { + buffer[0] = 0x01; + if (length != 1) { + LOGWARN("%s Received unexpected length: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, + GetController()->GetCmd(0), GetController()->GetCmd(1), GetController()->GetCmd(2), + GetController()->GetCmd(3), GetController()->GetCmd(4), GetController()->GetCmd(5)); + } + } else { + LOGWARN("%s Unhandled command received: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, + GetController()->GetCmd(0), GetController()->GetCmd(1), GetController()->GetCmd(2), + GetController()->GetCmd(3), GetController()->GetCmd(4), GetController()->GetCmd(5)); + buffer[0] = 0x00; + buffer[1] = 0x00; + buffer[2] = 0x00; + } + + // Set next block + //////ctrl->blocks = 1; + //////ctrl->next = 1; + + GetController()->SetBlocks(1); + GetController()->SetNext(1); + + //////controller->DataIn(); + EnterDataInPhase(); } - //--------------------------------------------------------------------------- // // Unknown Command C9 - Write a configuration value? // //--------------------------------------------------------------------------- -void SCSIPowerView::CmdWriteConfig(SASIDEV *controller) +void SCSIPowerView::CmdWriteConfig() { + // Set transfer amount + ////////ctrl->length = ctrl->cmd[6]; + int length = GetController()->GetCmd(6); + GetController()->SetLength(length); + LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, length); - // Set transfer amount - ctrl->length = ctrl->cmd[6]; - LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); + ///////if (ctrl->length == 0){ + if (length == 0) { + EnterStatusPhase(); + // controller->Status(); + } else { + GetController()->SetBlocks(1); + GetController()->SetNext(1); + // // Set next block + // ctrl->blocks = 1; + // ctrl->next = 1; - if (ctrl->length == 0){ - controller->Status(); - } - else - { - // Set next block - ctrl->blocks = 1; - ctrl->next = 1; + // controller->DataOut(); - controller->DataOut(); - } + EnterDataOutPhase(); + } } - - //--------------------------------------------------------------------------- // // Command to Write a Frame Buffer update // //--------------------------------------------------------------------------- -void SCSIPowerView::CmdWriteFramebuffer(SASIDEV *controller) +void SCSIPowerView::CmdWriteFramebuffer() { - // Make sure the receive buffer is big enough - if (ctrl->bufsize < POWERVIEW_BUFFER_SIZE) { - free(ctrl->buffer); - ctrl->bufsize = POWERVIEW_BUFFER_SIZE; - ctrl->buffer = (BYTE *)malloc(ctrl->bufsize); - } + // int bufsize = GetController()->GetBufferSize(); + // // Make sure the receive buffer is big enough + // if (ctrl->bufsize < POWERVIEW_BUFFER_SIZE) { + // free(ctrl->buffer); + // ctrl->bufsize = POWERVIEW_BUFFER_SIZE; + // ctrl->buffer = (uint8_t *)malloc(ctrl->bufsize); + // } - // Set transfer amount - uint16_t width_x = ctrl->cmd[5] + (ctrl->cmd[4] << 8); - uint16_t height_y = ctrl->cmd[7] + (ctrl->cmd[6] << 8); + GetController()->AllocateBuffer(POWERVIEW_BUFFER_SIZE); - ctrl->length = width_x * height_y; + // // Set transfer amount + // uint16_t width_x = ctrl->cmd[5] + (ctrl->cmd[4] << 8); + // uint16_t height_y = ctrl->cmd[7] + (ctrl->cmd[6] << 8); - LOGTRACE("%s Message Length %d [%08X]", __PRETTY_FUNCTION__, (int)ctrl->length, (unsigned int)ctrl->length); + uint16_t width_x = GetController()->GetCmd(5) + (GetController()->GetCmd(4) << 8); + uint16_t height_y = GetController()->GetCmd(7) + (GetController()->GetCmd(6) << 8); - if (ctrl->length <= 0) { - // Failure (Error) - controller->Error(); - return; - } + // ctrl->length = width_x * height_y; + int length = width_x * height_y; + GetController()->SetLength(length); - // Set next block - ctrl->blocks = 1; - ctrl->next = 1; + LOGTRACE("%s Message Length %d [%08X]", __PRETTY_FUNCTION__, length, length); - controller->DataOut(); + if (length <= 0) { + // Failure (Error) + // controller->Error(); + GetController()->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); + return; + } + + // Set next block + // ctrl->blocks = 1; + // ctrl->next = 1; + GetController()->SetBlocks(1); + GetController()->SetNext(1); + + // controller->DataOut(); + EnterDataOutPhase(); } - //--------------------------------------------------------------------------- // // Receive a new color palette from the host // //--------------------------------------------------------------------------- -void SCSIPowerView::CmdWriteColorPalette(SASIDEV *controller) +void SCSIPowerView::CmdWriteColorPalette() { + // eColorDepth_t received_color_depth = (eColorDepth_t)((uint16_t)ctrl->cmd[4] + ((uint16_t)ctrl->cmd[3] << 8)); + eColorDepth_t received_color_depth = + (eColorDepth_t)((uint16_t)GetController()->GetCmd(4) + ((uint16_t)GetController()->GetCmd(3) << 8)); + int length = (uint16_t)received_color_depth * 4; + GetController()->SetLength(length); + LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, length); - eColorDepth_t received_color_depth = (eColorDepth_t)((uint16_t)ctrl->cmd[4] + ((uint16_t)ctrl->cmd[3] << 8)); - ctrl->length = (uint16_t)received_color_depth * 4; - LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); + // The driver sends "1" for black and white, which is really + // TWO colors: Black and White + if (received_color_depth == eColorsBW) { + // ctrl->length = 8; + GetController()->SetLength(8); + } - // The driver sends "1" for black and white, which is really - // TWO colors: Black and White - if(received_color_depth == eColorsBW){ - ctrl->length = 8; - } + if (length <= 0) { + // Failure (Error) + // controller->Error(); - if (ctrl->length <= 0) { - // Failure (Error) - controller->Error(); - return; - } + GetController()->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); + return; + } - // Set next block - ctrl->blocks = 1; - ctrl->next = 1; + // Set next block + // ctrl->blocks = 1; + // ctrl->next = 1; + GetController()->SetBlocks(1); + GetController()->SetNext(1); - controller->DataOut(); + EnterDataOutPhase(); + // controller->DataOut(); } - //--------------------------------------------------------------------------- // // Unknown Command CC // //--------------------------------------------------------------------------- -void SCSIPowerView::UnknownCommandCC(SASIDEV *controller) +void SCSIPowerView::UnknownCommandCC() { - // Set transfer amount - ctrl->length = 0x8bb; - LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); - if (ctrl->length <= 0) { - // Failure (Error) - controller->Error(); - return; - } + // Set transfer amount + // ctrl->length = 0x8bb; + int length = 0x8bb; + GetController()->SetLength(length); + LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, length); + // if (ctrl->length <= 0) { + if (length <= 0) { + // Failure (Error) + // controller->Error(); + GetController()->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); - // Set next block - ctrl->blocks = 1; - ctrl->next = 1; + return; + } - controller->DataOut(); + // Set next block + // ctrl->blocks = 1; + // ctrl->next = 1; + GetController()->SetBlocks(1); + GetController()->SetNext(1); + + EnterDataOutPhase(); + // controller->DataOut(); } -bool SCSIPowerView::Dispatch(SCSIDEV *controller) +// bool SCSIPowerView::Dispatch(SCSIDEV *controller) +// { +// ctrl = controller->GetCtrl(); + +// if (commands.count(static_cast(ctrl->cmd[0]))) { +// command_t *command = commands[static_cast(ctrl->cmd[0])]; + +// LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]); + +// (this->*command->execute)(controller); + +// return true; +// } + +// LOGTRACE("%s Calling base class for dispatching $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->cmd[0]); + +// // The base class handles the less specific commands +// return Disk::Dispatch(controller); +// } + +bool SCSIPowerView::HwInit() { - ctrl = controller->GetCtrl(); + LOGTRACE("Entering %s", __PRETTY_FUNCTION__); - if (commands.count(static_cast(ctrl->cmd[0]))) { - command_t *command = commands[static_cast(ctrl->cmd[0])]; + this->fbfd = open("/dev/fb0", O_RDWR); + if (this->fbfd == -1) { + LOGWARN("Unable to open /dev/fb0. Do you have a monitor connected?"); + return false; + } + LOGTRACE("%s - /dev/fb0 opened", __PRETTY_FUNCTION__); - LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]); + if (ioctl(this->fbfd, FBIOGET_VSCREENINFO, &fbinfo)) { + LOGERROR("Unable to retrieve framebuffer v screen info. Are you running as root?"); + return false; + } - (this->*command->execute)(controller); + if (ioctl(this->fbfd, FBIOGET_FSCREENINFO, &fbfixinfo)) { + LOGERROR("Unable to retrieve framebuffer f screen info. Are you running as root?"); + return false; + } - return true; - } + if (fbinfo.bits_per_pixel != 16) { + LOGERROR("PowerView emulation only supports 16 bits per pixel framebuffer. Currently set to %d", + fbinfo.bits_per_pixel); + LOGERROR("Try running \"fbset -depth 16\""); + return false; + } - LOGTRACE("%s Calling base class for dispatching $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->cmd[0]); + LOGTRACE("%s Done capturing FB info", __PRETTY_FUNCTION__); - // The base class handles the less specific commands - return Disk::Dispatch(controller); -} + fbbpp = fbinfo.bits_per_pixel; + fblinelen = fbfixinfo.line_length; -bool SCSIPowerView::Init(const map& params) -{ - LOGTRACE("Entering %s", __PRETTY_FUNCTION__); - SetParams(params.empty() ? GetDefaultParams() : params); + fb = (char*)mmap(0, fbfixinfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); + if (fb == MAP_FAILED) { + LOGERROR("Unable to mmap the framebuffer memory. Are you running as root?"); + return false; + } + LOGTRACE("%s mmap complete", __PRETTY_FUNCTION__); - this->fbfd = open("/dev/fb0", O_RDWR); - if (this->fbfd == -1){ - LOGWARN("Unable to open /dev/fb0. Do you have a monitor connected?"); - return false; - } - LOGTRACE("%s - /dev/fb0 opened", __PRETTY_FUNCTION__); + // Clear the framebuffer + memset(this->fb, 0, fbfixinfo.smem_len); + LOGTRACE("%s done clearing framebuffer", __PRETTY_FUNCTION__); - if (ioctl(this->fbfd, FBIOGET_VSCREENINFO, &fbinfo)){ - LOGERROR("Unable to retrieve framebuffer v screen info. Are you running as root?"); - return false; - } + // Hide the flashing cursor on the screen + fbcon_cursor(false); - if (ioctl(this->fbfd, FBIOGET_FSCREENINFO, &fbfixinfo)){ - LOGERROR("Unable to retrieve framebuffer f screen info. Are you running as root?"); - return false; - } + // Disable the automatic screen blanking (screen saver) + fbcon_blank(false); + LOGTRACE("%s Done disable blanking", __PRETTY_FUNCTION__); - if (fbinfo.bits_per_pixel != 16){ - LOGERROR("PowerView emulation only supports 16 bits per pixel framebuffer. Currently set to %d", fbinfo.bits_per_pixel); - LOGERROR("Try running \"fbset -depth 16\""); - return false; - } + // Draw a blue frame around the display area + // This indicates that the PowerView simulation is running + ClearFrameBuffer(framebuffer_blue); - LOGTRACE("%s Done capturing FB info", __PRETTY_FUNCTION__); + // Report status to the screen + // char status_string[256]; + string status_string = fmt::format("PowerView initialized on {}x{} {} bpp framebuffer\r", fbinfo.xres, fbinfo.yres, + fbinfo.bits_per_pixel); + fbcon_text(status_string.c_str()); + LOGINFO("%s", status_string.c_str()); - fbbpp = fbinfo.bits_per_pixel; - fblinelen = fbfixinfo.line_length; - - fb = (char *)mmap(0, fbfixinfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); - if ((int)fb == -1){ - LOGERROR("Unable to mmap the framebuffer memory. Are you running as root?"); - return false; - } - LOGTRACE("%s mmap complete", __PRETTY_FUNCTION__); - - // Clear the framebuffer - memset(this->fb, 0, fbfixinfo.smem_len); - LOGTRACE("%s done clearing framebuffer", __PRETTY_FUNCTION__); - - // Hide the flashing cursor on the screen - fbcon_cursor(false); - - // Disable the automatic screen blanking (screen saver) - fbcon_blank(false); - LOGTRACE("%s Done disable blanking", __PRETTY_FUNCTION__); - - // Draw a blue frame around the display area - // This indicates that the PowerView simulation is running - ClearFrameBuffer(framebuffer_blue); - - // Report status to the screen - char status_string[256]; - sprintf(status_string, "PowerView initialized on %dx%d %d bpp framebuffer\r", fbinfo.xres, fbinfo.yres, fbinfo.bits_per_pixel); - fbcon_text(status_string); - LOGINFO(status_string); - - return true; + return true; } //--------------------------------------------------------------------------- @@ -436,386 +493,443 @@ bool SCSIPowerView::Init(const map& params) // INQUIRY // //--------------------------------------------------------------------------- -int SCSIPowerView::Inquiry(const DWORD *cdb, BYTE *buf) +// int SCSIPowerView::Inquiry(const uint32_t *cdb, uint8_t *buf) +vector SCSIPowerView::InquiryInternal() const { - int allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8); - if (allocation_length > 0) { - if ((unsigned int)allocation_length > sizeof(m_inquiry_response)) { - allocation_length = (int)sizeof(m_inquiry_response); - } + vector buf = HandleInquiry(device_type::PROCESSOR, scsi_level::SCSI_2, false); - memcpy(buf, m_inquiry_response, allocation_length); + int allocation_length = GetController()->GetCmd(4) + (((uint32_t)GetController()->GetCmd(3)) << 8); + if (allocation_length > 0) { + if ((unsigned int)allocation_length > sizeof(m_inquiry_response)) { + allocation_length = (int)sizeof(m_inquiry_response); + } - // // Basic data - // // buf[0] ... Processor Device - // // buf[1] ... Not removable - // // buf[2] ... SCSI-2 compliant command system - // // buf[3] ... SCSI-2 compliant Inquiry response - // // buf[4] ... Inquiry additional data - // // http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/pocket_scsiLINK/pocketscsilink_inq.png - // memset(buf, 0, allocation_length); - // buf[0] = 0x03; - // buf[2] = 0x01; - // buf[4] = 0x1F; + memcpy(buf.data(), m_inquiry_response, allocation_length); - // // Padded vendor, product, revision - // memcpy(&buf[8], GetPaddedName().c_str(), 28); - } + // // Basic data + // // buf[0] ... Processor Device + // // buf[1] ... Not removable + // // buf[2] ... SCSI-2 compliant command system + // // buf[3] ... SCSI-2 compliant Inquiry response + // // buf[4] ... Inquiry additional data + // // http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/pocket_scsiLINK/pocketscsilink_inq.png + // memset(buf, 0, allocation_length); + // buf[0] = 0x03; + // buf[2] = 0x01; + // buf[4] = 0x1F; - LOGTRACE("response size is %d", allocation_length); + // // Padded vendor, product, revision + // memcpy(&buf[8], GetPaddedName().c_str(), 28); + } - return allocation_length; + LOGTRACE("%s response size is %d", __PRETTY_FUNCTION__, allocation_length); + + return buf; } - -bool SCSIPowerView::WriteConfiguration(const DWORD *cdb, const BYTE *buf, const DWORD length) +bool SCSIPowerView::WriteConfiguration() { + // const uint32_t *cdb, const uint8_t *buf, const uint32_t length + // vector& cdb = GetController()->GetCmd(); + vector& buf = GetController()->GetBuffer(); + int length = GetController()->GetCmd(6); // TODO: Is this right? - std::stringstream ss; + std::stringstream ss; ss << std::hex; - for( DWORD i(0) ; i < length; ++i ){ - ss << std::setw(2) << std::setfill('0') << (int)buf[i]; - } + for (int i(0); i < length; ++i) { + ss << std::setw(2) << std::setfill('0') << (int)buf[i]; + } - LOGDEBUG("%s Received Config Write of length %d: %s",__PRETTY_FUNCTION__, length, ss.str().c_str()); - - return true; + LOGDEBUG("%s Received Config Write of length %d: %s", __PRETTY_FUNCTION__, length, ss.str().c_str()); + return true; } -bool SCSIPowerView::WriteUnknownCC(const DWORD *cdb, const BYTE *buf, const DWORD length) +bool SCSIPowerView::WriteUnknownCC() { + // const uint32_t *cdb, const uint8_t *buf, const uint32_t length + // vector& cdb = GetController()->GetCmd(); + vector& buf = GetController()->GetBuffer(); + int length = GetController()->GetCmd(6); // TODO: Is this right? - if(length > sizeof(unknown_cc_data)){ - LOGERROR("%s Received Unknown CC data that is larger (%d bytes) than allocated size (%d bytes)", __PRETTY_FUNCTION__, length, sizeof(unknown_cc_data)); - return false; - } + if (length > (int)sizeof(unknown_cc_data)) { + LOGERROR("%s Received Unknown CC data that is larger (%d bytes) than allocated size (%d bytes)", + __PRETTY_FUNCTION__, length, (int)sizeof(unknown_cc_data)); + return false; + } - LOGINFO("%s Unknown CC of size %ul received", __PRETTY_FUNCTION__, length); - memcpy(unknown_cc_data, buf, length); - unknown_cc_data_length = length; - return true; + LOGINFO("%s Unknown CC of size %ul received", __PRETTY_FUNCTION__, length); + memcpy(unknown_cc_data, buf.data(), length); + unknown_cc_data_length = length; + return true; } - -bool SCSIPowerView::WriteColorPalette(const DWORD *cdb, const BYTE *buf, const DWORD length) +bool SCSIPowerView::WriteColorPalette() { + // const uint32_t *cdb, const uint8_t *buf, const uint32_t length + vector& cdb = GetController()->GetCmd(); + // vector& buf = GetController()->GetBuffer(); + int length = GetController()->GetCmd(6); // TODO: Is this right? - if(length <= 1){ - LOGDEBUG("%s Received Color Palette with depth of %u", __PRETTY_FUNCTION__, length); - // This is still a valid condition. - return true; - } - if(length > sizeof(color_palette)){ - LOGERROR("%s Received Color Palette that is larger (%d bytes) than allocated size (%d bytes)", __PRETTY_FUNCTION__, length, sizeof(color_palette)); - return false; - } + if (length <= 1) { + LOGDEBUG("%s Received Color Palette with depth of %u", __PRETTY_FUNCTION__, length); + // This is still a valid condition. + return true; + } + if (length > (int)sizeof(color_palette)) { + LOGERROR("%s Received Color Palette that is larger (%d bytes) than allocated size (%d bytes)", + __PRETTY_FUNCTION__, length, (int)sizeof(color_palette)); + return false; + } - eColorDepth_t new_color = (eColorDepth_t)((uint16_t)cdb[4] + ((uint16_t)cdb[3] << 8)); + eColorDepth_t new_color = (eColorDepth_t)((uint16_t)cdb[4] + ((uint16_t)cdb[3] << 8)); - if(new_color == eColorDepth_t::eColorsNone){ - // This is currently unknown functionality. So, just ignore it. - return true; - } - - ClearFrameBuffer(framebuffer_red); + if (new_color == eColorDepth_t::eColorsNone) { + // This is currently unknown functionality. So, just ignore it. + return true; + } - color_depth = new_color; + ClearFrameBuffer(framebuffer_red); - switch(color_depth){ - case eColorsBW: - memcpy(color_palette, default_color_palette_bw, sizeof(default_color_palette_bw)); - break; - case eColors16: - memcpy(color_palette, default_color_palette_16, sizeof(default_color_palette_16)); - break; - case eColors256: - memcpy(color_palette, default_color_palette_256, sizeof(default_color_palette_256)); - break; - default: - LOGWARN("UNHANDLED COLOR DEPTH: %04X", color_depth); - break; - } + color_depth = new_color; - // memcpy(color_palette, buf, length); - // color_palette_length = length; - // memcpy(color_palette, default_color_palette_256, sizeof(default_color_palette_256)); + switch (color_depth) { + case eColorsBW: + memcpy(color_palette, default_color_palette_bw, sizeof(default_color_palette_bw)); + break; + case eColors16: + memcpy(color_palette, default_color_palette_16, sizeof(default_color_palette_16)); + break; + case eColors256: + memcpy(color_palette, default_color_palette_256, sizeof(default_color_palette_256)); + break; + default: + LOGWARN("UNHANDLED COLOR DEPTH: %04X", color_depth); + break; + } - LOGINFO("%s Color type: %04x Palette of size %ul received", __PRETTY_FUNCTION__, (uint16_t)cdb[4] + ((uint16_t)cdb[3] << 8), length); + // memcpy(color_palette, buf, length); + // color_palette_length = length; + // memcpy(color_palette, default_color_palette_256, sizeof(default_color_palette_256)); + + LOGINFO("%s Color type: %04x Palette of size %ul received", __PRETTY_FUNCTION__, + (uint16_t)cdb[4] + ((uint16_t)cdb[3] << 8), length); #ifdef DUMP_COLOR_PALETTE - FILE *fp; - char newstring[1024]; - static int dump_idx = 0; + FILE* fp; + char newstring[1024]; + static int dump_idx = 0; - switch(color_depth){ - case(eColorsBW): - sprintf(newstring, "/tmp/eColorsBW_%04X.txt",dump_idx++); - break; - case(eColors16): - sprintf(newstring, "/tmp/eColors16_%04X.txt",dump_idx++); - break; - case(eColors256): - sprintf(newstring, "/tmp/eColors256_%04X.txt",dump_idx++); - break; - default: - return false; - break; - } - //LOGWARN(newstring); - fp = fopen(newstring,"w"); + switch (color_depth) { + case (eColorsBW): + sprintf(newstring, "/tmp/eColorsBW_%04X.txt", dump_idx++); + break; + case (eColors16): + sprintf(newstring, "/tmp/eColors16_%04X.txt", dump_idx++); + break; + case (eColors256): + sprintf(newstring, "/tmp/eColors256_%04X.txt", dump_idx++); + break; + default: + return false; + break; + } + // LOGWARN(newstring); + fp = fopen(newstring, "w"); - sprintf(newstring, "length: %u\n", length); + sprintf(newstring, "length: %u\n", length); - fputs(newstring, fp); + fputs(newstring, fp); - for(DWORD i = 0; i < length; i+=4){ - if(i % 16 == 0){ - sprintf(newstring, "%u: ", i); - fputs(newstring,fp); - } + for (uint32_t i = 0; i < length; i += 4) { + if (i % 16 == 0) { + sprintf(newstring, "%u: ", i); + fputs(newstring, fp); + } - sprintf(newstring, "[%02X %02X%02X%02X] ", buf[i+0],buf[i+1],buf[i+2],buf[i+3]); - fputs(newstring, fp); + sprintf(newstring, "[%02X %02X%02X%02X] ", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3]); + fputs(newstring, fp); - if(i % 16 == 12){ - - fputs("\n", fp); - } - } - fclose(fp); + if (i % 16 == 12) { + fputs("\n", fp); + } + } + fclose(fp); #endif - return true; + return true; } - -bool SCSIPowerView::WriteFrameBuffer(const DWORD *cdb, const BYTE *buf, const DWORD length) +bool SCSIPowerView::WriteFrameBuffer() { - char newstring[1024]; + // const uint32_t *cdb, const uint8_t *buf, const uint32_t length + + vector& cdb = GetController()->GetCmd(); + vector& buf = GetController()->GetBuffer(); + // int length = GetController()->GetCmd(6); // TODO: Is this right? + + char newstring[1024]; // uint32_t new_screen_width_px =0; - // uint32_t new_screen_height_px=0; - uint32_t update_width_px=0; - uint32_t update_height_px=0; - uint32_t offset_row_px = 0; - uint32_t offset_col_px = 0; + // uint32_t new_screen_height_px=0; + uint32_t update_width_px = 0; + uint32_t update_height_px = 0; + uint32_t offset_row_px = 0; + uint32_t offset_col_px = 0; - // Set transfer amount - uint32_t update_width_x_bytes = ctrl->cmd[5] + (ctrl->cmd[4] << 8); - uint32_t update_height_y_bytes = ctrl->cmd[7] + (ctrl->cmd[6] << 8); - uint32_t offset = (uint32_t)ctrl->cmd[3] + ((uint32_t)ctrl->cmd[2] << 8) + ((uint32_t)ctrl->cmd[1] << 16); + // Set transfer amount + // uint32_t update_width_x_bytes = ctrl->cmd[5] + (ctrl->cmd[4] << 8); + // uint32_t update_height_y_bytes = ctrl->cmd[7] + (ctrl->cmd[6] << 8); + // uint32_t offset = (uint32_t)ctrl->cmd[3] + ((uint32_t)ctrl->cmd[2] << 8) + ((uint32_t)ctrl->cmd[1] << 16); + LOGWARN("THIS ISN'T RIGHT!!!") + uint32_t update_width_x_bytes = 0; // cmd[5] + (cmd[4] << 8); + uint32_t update_height_y_bytes = 0; // cmd[7] + (cmd[6] << 8); + uint32_t offset = 0; //(uint32_t)cmd[3] + ((uint32_t)cmd[2] << 8) + ((uint32_t)cmd[1] << 16); - bool full_framebuffer_refresh = (offset == 0) && (cdb[9] == 0x00); + bool full_framebuffer_refresh = (offset == 0) && (cdb[9] == 0x00); + switch (color_depth) { + case (eColorsBW): + // One bit per pixel + update_width_px = update_width_x_bytes * 8; + offset_row_px = (uint32_t)((offset * 8) / screen_width_px) / 2; + offset_col_px = (uint32_t)(((offset * 8) / 2) % screen_width_px); + break; + case (eColors16): + // One byte per pixel + update_width_px = update_width_x_bytes * 2; + offset_row_px = (uint32_t)((offset * 2) / screen_width_px) / 2; + offset_col_px = (uint32_t)(((offset * 2) / 2) % screen_width_px); + break; + case (eColors256): + // Two Bytes per pixel + update_width_px = update_width_x_bytes; + offset_row_px = (uint32_t)(offset / screen_width_px); + offset_col_px = (uint32_t)(offset % screen_width_px); + break; + default: + update_width_px = 0; + offset_row_px = 0; + offset_col_px = 0; + LOGINFO("No color depth available! %04X", color_depth); + break; + } + update_height_px = update_height_y_bytes; - switch(color_depth){ - case(eColorsBW): - // One bit per pixel - update_width_px = update_width_x_bytes * 8; - offset_row_px = (uint32_t)((offset*8) / screen_width_px)/2; - offset_col_px = (uint32_t)(((offset*8)/2) % screen_width_px); - break; - case(eColors16): - // One byte per pixel - update_width_px = update_width_x_bytes * 2; - offset_row_px = (uint32_t)((offset*2) / screen_width_px)/2; - offset_col_px = (uint32_t)(((offset*2)/2) % screen_width_px); - break; - case(eColors256): - // Two Bytes per pixel - update_width_px = update_width_x_bytes; - offset_row_px = (uint32_t)(offset / screen_width_px); - offset_col_px = (uint32_t)(offset % screen_width_px); - break; - default: - update_width_px = 0; - offset_row_px = 0; - offset_col_px = 0; - LOGINFO("No color depth available! %04X", color_depth); - break; - } - update_height_px = update_height_y_bytes; + if (full_framebuffer_refresh) { + screen_width_px = update_width_px; + screen_height_px = update_height_px; + switch (color_depth) { + case eColorDepth_t::eColorsBW: + sprintf(newstring, " Black & White %04X - %u x %u \r", color_depth, + screen_width_px, screen_height_px); + break; + case eColorDepth_t::eColors16: + sprintf(newstring, " 16 colors/grays %04X - %u x %u \r", color_depth, + screen_width_px, screen_height_px); + break; + case eColorDepth_t::eColors256: + sprintf(newstring, " 256 colors/grays %04X - %u x %u \r", color_depth, + screen_width_px, screen_height_px); + break; + default: + sprintf(newstring, " UNKNOWN COLOR DEPTH!! %04X - %u x %u \r", color_depth, + screen_width_px, screen_height_px); + break; + } + fbcon_text(newstring); + } - if(full_framebuffer_refresh){ - screen_width_px = update_width_px; - screen_height_px = update_height_px; + LOGTRACE("Calculate Offset: %u (%08X) Screen width: %u height: %u Update X: %u (%06X) Y: %u (%06X)", offset, offset, + screen_width_px, screen_height_px, offset_row_px, offset_row_px, offset_col_px, offset_col_px); - switch(color_depth){ - case eColorDepth_t::eColorsBW: - sprintf(newstring, " Black & White %04X - %u x %u \r", color_depth, screen_width_px, screen_height_px); - break; - case eColorDepth_t::eColors16: - sprintf(newstring, " 16 colors/grays %04X - %u x %u \r", color_depth, screen_width_px,screen_height_px ); - break; - case eColorDepth_t::eColors256: - sprintf(newstring, " 256 colors/grays %04X - %u x %u \r", color_depth, screen_width_px, screen_height_px); - break; - default: - sprintf(newstring, " UNKNOWN COLOR DEPTH!! %04X - %u x %u \r", color_depth, screen_width_px, screen_height_px); - break; - } - fbcon_text(newstring); + if (update_width_px == 0) { + // This is some weird error condition. For now, just return. + LOGWARN("update of size 0 received, or there is no color depth"); + return true; + } - } + if (update_height_px + offset_row_px > 800) { + LOGWARN("%s Height: (%d + %d) = %d is larger than the limit", __PRETTY_FUNCTION__, update_height_px, + offset_row_px, update_height_px + offset_row_px); + return true; + } + if (update_width_px + offset_col_px > 800) { + // We can get into this condition when the color depth has not been set by the host. We can try + // to derive it based upon the screen width + if (color_depth == eColorsBW) { + if ((update_width_px == (800 * 8)) || (update_width_px == (640 * 8)) || (update_width_px == (600 * 8))) { + color_depth = eColors256; + // We don't know if we're 256 grays or 256 colors. So, this could be goofy looking + // We're down in an error condition anyway. + LOGINFO("Based upon size of screen update, switching to 256 colors. This may be incorrect if the " + "screen is supposed to be 256 grays"); + memcpy(color_palette, default_color_palette_256, sizeof(default_color_palette_256)); + // Try it again.... (Re-call this function) + return WriteFrameBuffer(); + } + if ((update_width_px == (800 * 2)) || (update_width_px == (640 * 2)) || (update_width_px == (600 * 2))) { + color_depth = eColors16; + LOGINFO("Based upon size of screen update, switching to 16 colors. This may be incorrect if the screen " + "is supposed to be 16 grays"); + memcpy(color_palette, default_color_palette_16, sizeof(default_color_palette_16)); + // Try it again.... (Re-call this function) + return WriteFrameBuffer(); + } + } - LOGTRACE("Calculate Offset: %u (%08X) Screen width: %u height: %u Update X: %u (%06X) Y: %u (%06X)", offset, offset, screen_width_px, screen_height_px, offset_row_px, offset_row_px, offset_col_px, offset_col_px); + LOGWARN("%s width: (%d + %d) = %d is larger than the limit", __PRETTY_FUNCTION__, update_width_px, + offset_col_px, update_width_px + offset_col_px); + return true; + } - if(update_width_px == 0){ - // This is some weird error condition. For now, just return. - LOGWARN("update of size 0 received, or there is no color depth"); - return true; - } + LOGDEBUG("Update Position: %d:%d Offset: %d Screen Width: %d Width px: %d:%d (bytes: %d, %d)", offset_col_px, + offset_row_px, offset, screen_width_px, update_width_px, update_height_px, update_width_x_bytes, + update_height_y_bytes); - if(update_height_px + offset_row_px > 800){ - LOGWARN("%s Height: (%d + %d) = %d is larger than the limit", __PRETTY_FUNCTION__, update_height_px, offset_row_px, update_height_px + offset_row_px); - return true; - } - if(update_width_px + offset_col_px > 800){ - // We can get into this condition when the color depth has not been set by the host. We can try - // to derive it based upon the screen width - if(color_depth == eColorsBW){ - if((update_width_px == (800 * 8)) || (update_width_px == (640 * 8)) || (update_width_px == (600 * 8))){ - color_depth = eColors256; - // We don't know if we're 256 grays or 256 colors. So, this could be goofy looking - // We're down in an error condition anyway. - LOGINFO("Based upon size of screen update, switching to 256 colors. This may be incorrect if the screen is supposed to be 256 grays"); - memcpy(color_palette, default_color_palette_256, sizeof(default_color_palette_256)); - // Try it again.... (Re-call this function) - return WriteFrameBuffer(cdb, buf, length); - } - if((update_width_px == (800 * 2)) || (update_width_px == (640 * 2)) || (update_width_px == (600 * 2))){ - color_depth = eColors16; - LOGINFO("Based upon size of screen update, switching to 16 colors. This may be incorrect if the screen is supposed to be 16 grays"); - memcpy(color_palette, default_color_palette_16, sizeof(default_color_palette_16)); - // Try it again.... (Re-call this function) - return WriteFrameBuffer(cdb, buf, length); - } - } + uint32_t random_print = rand() % (update_height_px * update_width_px); - LOGWARN("%s width: (%d + %d) = %d is larger than the limit", __PRETTY_FUNCTION__, update_width_px, offset_col_px, update_width_px + offset_col_px); - return true; - } + // For each row + for (uint32_t idx_row_y = 0; idx_row_y < (update_height_px); idx_row_y++) { + // For each column + for (uint32_t idx_col_x = 0; idx_col_x < (update_width_px); idx_col_x++) { + uint32_t pixel_color_idx = 0; + uint32_t pixel_buffer_idx = 0; + uint8_t pixel_buffer_byte = 0; + uint32_t pixel_bit_number = 0; + uint32_t loc = 0; - LOGDEBUG("Update Position: %d:%d Offset: %d Screen Width: %d Width px: %d:%d (bytes: %d, %d)", offset_col_px, offset_row_px, offset, screen_width_px, update_width_px, update_height_px, update_width_x_bytes, update_height_y_bytes); + switch (color_depth) { + case eColorDepth_t::eColorsBW: + pixel_buffer_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x / 8); + pixel_buffer_byte = reverse_table[buf[pixel_buffer_idx]]; + pixel_bit_number = idx_col_x % 8; + pixel_color_idx = ((pixel_buffer_byte >> pixel_bit_number) & 0x1) ? 0 : 1; + break; - DWORD random_print = rand() % (update_height_px * update_width_px); + case eColorDepth_t::eColors16: + pixel_buffer_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x / 2); + if (idx_col_x % 2) { + pixel_color_idx = buf[pixel_buffer_idx] & 0x0F; + } else { + pixel_color_idx = buf[pixel_buffer_idx] >> 4; + } + break; + case eColorDepth_t::eColors256: + pixel_buffer_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x); + pixel_color_idx = buf[pixel_buffer_idx]; + break; + default: + break; + } - // For each row - for (DWORD idx_row_y = 0; idx_row_y < (update_height_px); idx_row_y++){ + if (pixel_color_idx > (sizeof(color_palette) / sizeof(color_palette[0]))) { + LOGWARN("Calculated pixel color that is out of bounds: %04X", pixel_buffer_idx); + return false; + } - // For each column - for (DWORD idx_col_x = 0; idx_col_x < (update_width_px); idx_col_x++){ - BYTE pixel_color_idx=0; - DWORD pixel_buffer_idx = 0; - BYTE pixel_buffer_byte = 0; - DWORD pixel_bit_number = 0; - uint32_t loc = 0; + loc = ((idx_col_x + offset_col_px) * (this->fbbpp / 8)) + ((idx_row_y + offset_row_px) * fblinelen); - switch(color_depth){ - case eColorDepth_t::eColorsBW: - pixel_buffer_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x / 8); - pixel_buffer_byte = reverse_table[buf[pixel_buffer_idx]]; - pixel_bit_number = idx_col_x % 8; - pixel_color_idx = ((pixel_buffer_byte >> pixel_bit_number) & 0x1) ? 0 : 1; - break; + uint32_t data_idx, red, green, blue; - case eColorDepth_t::eColors16: - pixel_buffer_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x/2); - if(idx_col_x % 2){ - pixel_color_idx = buf[pixel_buffer_idx] & 0x0F; - } - else{ - pixel_color_idx = buf[pixel_buffer_idx] >> 4; - } - break; - case eColorDepth_t::eColors256: - pixel_buffer_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x); - pixel_color_idx = buf[pixel_buffer_idx]; - break; - default: - break; - } + data_idx = (uint32_t)color_palette[(pixel_color_idx * 4)]; + red = (uint32_t)color_palette[(pixel_color_idx * 4) + 1]; + green = (uint32_t)color_palette[(pixel_color_idx * 4) + 2]; + blue = (uint32_t)color_palette[(pixel_color_idx * 4) + 3]; - if(pixel_color_idx > (sizeof(color_palette) / sizeof (color_palette[0]))){ - LOGWARN("Calculated pixel color that is out of bounds: %04X", pixel_buffer_idx); - return false; - } + blue >>= (8 - fbinfo.red.length); + green >>= (8 - fbinfo.green.length); + red >>= (8 - fbinfo.blue.length); - loc = ((idx_col_x + offset_col_px) * (this->fbbpp / 8)) + ((idx_row_y + offset_row_px) * fblinelen); + uint32_t fb_pixel = + (red << fbinfo.red.offset) | (green << fbinfo.green.offset) | (blue << fbinfo.blue.offset); - uint32_t data_idx, red, green, blue; + if (random_print == (idx_col_x * idx_row_y)) { + LOGDEBUG("idx:%d (%02X) [%02X %02X %02X %02X] fb_pixel:%08X ", pixel_color_idx, pixel_color_idx, + data_idx, red, green, blue, fb_pixel); + } - data_idx = (uint32_t)color_palette[(pixel_color_idx*4)]; - red = (uint32_t)color_palette[(pixel_color_idx*4)+1]; - green = (uint32_t)color_palette[(pixel_color_idx*4)+2]; - blue = (uint32_t)color_palette[(pixel_color_idx*4)+3]; - - blue >>= (8 - fbinfo.red.length); - green >>= (8 - fbinfo.green.length); - red >>= (8 - fbinfo.blue.length); - - uint32_t fb_pixel = (red << fbinfo.red.offset) | - (green << fbinfo.green.offset)| - (blue << fbinfo.blue.offset); - - if(random_print == (idx_col_x * idx_row_y)){ - LOGDEBUG("idx:%d (%02X) [%02X %02X %02X %02X] fb_pixel:%08X ", pixel_color_idx, pixel_color_idx, data_idx, red, green, blue, fb_pixel); - } - - *(this->fb + loc + 1) = (BYTE)((fb_pixel >> 8) & 0xFF); - *(this->fb + loc + 0) = (BYTE)((fb_pixel) & 0xFF); - - } - } + *(this->fb + loc + 1) = (uint8_t)((fb_pixel >> 8) & 0xFF); + *(this->fb + loc + 0) = (uint8_t)((fb_pixel)&0xFF); + } + } #ifdef DUMP_FRAME_BUFFER - //****************************************************************************** - FILE *fp; + //****************************************************************************** + FILE* fp; - static int dumpfb_idx = 0; + static int dumpfb_idx = 0; - switch(color_depth){ - case(eColorsBW): - sprintf(newstring, "/tmp/fb_eColorsBW_%04X_%ux%u.txt",dumpfb_idx++, update_width_x_bytes, update_height_y_bytes); - break; - case(eColors16): - sprintf(newstring, "/tmp/fb_eColors16_%04X_%ux%u.txt",dumpfb_idx++, update_width_x_bytes, update_height_y_bytes); - break; - case(eColors256): - sprintf(newstring, "/tmp/fb_eColors256_%04X_%ux%u.txt",dumpfb_idx++, update_width_x_bytes, update_height_y_bytes); - break; - default: - return false; - break; - } - //LOGWARN(newstring); - fp = fopen(newstring,"w"); + switch (color_depth) { + case (eColorsBW): + sprintf(newstring, "/tmp/fb_eColorsBW_%04X_%ux%u.txt", dumpfb_idx++, update_width_x_bytes, + update_height_y_bytes); + break; + case (eColors16): + sprintf(newstring, "/tmp/fb_eColors16_%04X_%ux%u.txt", dumpfb_idx++, update_width_x_bytes, + update_height_y_bytes); + break; + case (eColors256): + sprintf(newstring, "/tmp/fb_eColors256_%04X_%ux%u.txt", dumpfb_idx++, update_width_x_bytes, + update_height_y_bytes); + break; + default: + return false; + break; + } + // LOGWARN(newstring); + fp = fopen(newstring, "w"); - sprintf(newstring, "length: %u\n", length); + sprintf(newstring, "length: %u\n", length); - fputs(newstring, fp); + fputs(newstring, fp); - for(DWORD i = 0; i < length; i+=4){ - if(i % 16 == 0){ - sprintf(newstring, "%u: ", i); - fputs(newstring,fp); - } + for (uint32_t i = 0; i < length; i += 4) { + if (i % 16 == 0) { + sprintf(newstring, "%u: ", i); + fputs(newstring, fp); + } - sprintf(newstring, "[%02X %02X %02X %02X] ", buf[i+0],buf[i+1],buf[i+2],buf[i+3]); - fputs(newstring, fp); + sprintf(newstring, "[%02X %02X %02X %02X] ", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3]); + fputs(newstring, fp); - if(i % 16 == 12){ - - fputs("\n", fp); - } - } - fclose(fp); + if (i % 16 == 12) { + fputs("\n", fp); + } + } + fclose(fp); #endif + //****************************************************************************** - //****************************************************************************** + return true; +} + +bool SCSIPowerView::WriteBytes(const vector& cdb, vector& buf, uint32_t) +{ + (void)cdb; + (void)buf; + // const int data_format = cdb[5]; + // int data_length = GetInt16(cdb, 3); + + // if (data_format == 0x00) { + // m_tap.Send(buf.data(), data_length); + // GetLogger().Trace("Transmitted " + to_string(data_length) + " byte(s) (00 format)"); + // } + // else if (data_format == 0x80) { + // // The data length is specified in the first 2 bytes of the payload + // data_length = buf[1] + ((static_cast(buf[0]) & 0xff) << 8); + // m_tap.Send(&(buf.data()[4]), data_length); + // GetLogger().Trace("Transmitted " + to_string(data_length) + "byte(s) (80 format)"); + // } + // else { + // stringstream s; + // s << "Unknown data format: " << setfill('0') << setw(2) << hex << data_format; + // GetLogger().Warn(s.str()); + // } + + GetController()->SetBlocks(0); return true; -} +} \ No newline at end of file diff --git a/cpp/devices/scsi_powerview.h b/cpp/devices/scsi_powerview.h index b0b0b1e9..fe70cee1 100644 --- a/cpp/devices/scsi_powerview.h +++ b/cpp/devices/scsi_powerview.h @@ -1,9 +1,8 @@ //--------------------------------------------------------------------------- // -// SCSI Target Emulator RaSCSI (*^..^*) -// for Raspberry Pi +// SCSI Target Emulator PiSCSI for Raspberry Pi // -// Copyright (C) 2020-2021 akuker +// Copyright (C) 2020-2023 akuker // Copyright (C) 2020 joshua stein // // Licensed under the BSD 3-Clause License. @@ -19,11 +18,11 @@ //--------------------------------------------------------------------------- #pragma once -#include "os.h" -#include "disk.h" +#include "interfaces/byte_writer.h" +#include "primary_device.h" + #include #include -#include "../rascsi.h" #include //=========================================================================== @@ -31,24 +30,24 @@ // Radius PowerView // //=========================================================================== -class SCSIPowerView: public Disk +class SCSIPowerView : public PrimaryDevice, public ByteWriter { private: - typedef struct _command_t { - const char* name; - void (SCSIPowerView::*execute)(SASIDEV *); + // typedef struct _command_t { + // const char* name; + // void (SCSIPowerView::*execute)(SASIDEV *); - _command_t(const char* _name, void (SCSIPowerView::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { }; - } command_t; - std::map commands; + // _command_t(const char* _name, void (SCSIPowerView::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { }; + // } command_t; + // std::map commands; - SASIDEV::ctrl_t *ctrl; + // SASIDEV::ctrl_t *ctrl; enum eColorDepth_t : uint16_t {eColorsNone=0x0000, eColorsBW=0x0001, eColors16=0x0010, eColors256=0x0100}; - void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSIPowerView::*)(SASIDEV *)); + // void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSIPowerView::*)(SASIDEV *)); // Largest framebuffer supported by the Radius PowerView is 800x600 at 256 colors (1 bytes per pixel) // Double it for now, because memory is cheap.... @@ -57,32 +56,47 @@ private: void fbcon_cursor(bool blank); void fbcon_blank(bool blank); - void fbcon_text(char* message); + void fbcon_text(const char* message); public: - SCSIPowerView(); - ~SCSIPowerView(); - bool Init(const map&) override; + + explicit SCSIPowerView(int); + ~SCSIPowerView() override; + + bool Init(const unordered_map&) override; + bool HwInit(); + + + // Commands + vector InquiryInternal() const override; + // int Read(const vector&, vector&, uint64_t); + bool WriteBytes(const vector&, vector&, uint32_t) override; + + // int RetrieveStats(const vector&, vector&) const; + + // void TestUnitReady() override; + // void Read6(); + // void Write6() const; + + // // Commands - int Inquiry(const DWORD *cdb, BYTE *buffer) override; - bool WriteFrameBuffer(const DWORD *cdb, const BYTE *buf, const DWORD length); - bool WriteColorPalette(const DWORD *cdb, const BYTE *buf, const DWORD length); - bool WriteConfiguration(const DWORD *cdb, const BYTE *buf, const DWORD length); - bool WriteUnknownCC(const DWORD *cdb, const BYTE *buf, const DWORD length); + // old..... int Inquiry(const uint32_t *cdb, uint8_t *buffer) override; + bool WriteFrameBuffer(); + bool WriteColorPalette(); + bool WriteConfiguration(); + bool WriteUnknownCC(); - void CmdReadConfig(SASIDEV *controller); - void CmdWriteConfig(SASIDEV *controller); - void CmdWriteFramebuffer(SASIDEV *controller); - void CmdWriteColorPalette(SASIDEV *controller); - void UnknownCommandCC(SASIDEV *controller); - - bool Dispatch(SCSIDEV *) override; + void CmdReadConfig(); + void CmdWriteConfig(); + void CmdWriteFramebuffer(); + void CmdWriteColorPalette(); + void UnknownCommandCC(); private: - void ClearFrameBuffer(DWORD blank_color); + void ClearFrameBuffer(uint32_t blank_color); // Default to the lowest resolution supported by the PowerView (640x400) uint32_t screen_width_px = 640; @@ -93,15 +107,15 @@ private: struct fb_fix_screeninfo fbfixinfo; // The maximum color depth is 16 bits - BYTE color_palette[0x10000]; - int color_palette_length = 0; + uint8_t color_palette[0x10000]; + // int color_palette_length = 0; - BYTE unknown_cc_data[0x10000]; + uint8_t unknown_cc_data[0x10000]; int unknown_cc_data_length = 0; - static const BYTE default_color_palette_bw[8]; - static const BYTE default_color_palette_16[64]; - static const BYTE default_color_palette_256[1024]; + static const uint8_t default_color_palette_bw[8]; + static const uint8_t default_color_palette_16[64]; + static const uint8_t default_color_palette_256[1024]; int fbfd; char *fb; @@ -109,12 +123,12 @@ private: int fbbpp; // Hard-coded inquiry response to match the real PowerView - static const BYTE m_inquiry_response[]; + static const uint8_t m_inquiry_response[]; static unsigned char reverse_table[256]; - DWORD framebuffer_black; - DWORD framebuffer_blue; - DWORD framebuffer_yellow; - DWORD framebuffer_red; + uint32_t framebuffer_black; + uint32_t framebuffer_blue; + uint32_t framebuffer_yellow; + uint32_t framebuffer_red; }; diff --git a/cpp/devices/scsi_powerview_palettes.cpp b/cpp/devices/scsi_powerview_palettes.cpp index 584a8842..bf65e6f8 100644 --- a/cpp/devices/scsi_powerview_palettes.cpp +++ b/cpp/devices/scsi_powerview_palettes.cpp @@ -1,11 +1,10 @@ //--------------------------------------------------------------------------- // -// SCSI Target Emulator RaSCSI (*^..^*) -// for Raspberry Pi +// SCSI Target Emulator PiSCSI for Raspberry Pi // -// Copyright (C) 2021 akuker +// Copyright (C) 2021-2023 akuker // -// Licensed under the BSD 3-Clause License. +// Licensed under the BSD 3-Clause License. // See LICENSE file in the project root folder. // // [ Default color palettes for the Radius PowerView SCSI Display Adapter ] @@ -13,83 +12,71 @@ //--------------------------------------------------------------------------- #include "scsi_powerview.h" +#include -const BYTE SCSIPowerView::default_color_palette_bw[8] = { - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF +const uint8_t SCSIPowerView::default_color_palette_bw[8] = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; + +const uint8_t SCSIPowerView::default_color_palette_16[64] = { + 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFC, 0xF3, 0x05, 0x02, 0xFF, 0x64, 0x02, 0x03, 0xDD, 0x08, 0x06, + 0x04, 0xF2, 0x08, 0x84, 0x05, 0x46, 0x00, 0xA5, 0x06, 0x00, 0x00, 0xD4, 0x07, 0x02, 0xAB, 0xEA, + 0x08, 0x1F, 0xB7, 0x14, 0x09, 0x00, 0x64, 0x11, 0x0A, 0x56, 0x2C, 0x05, 0x0B, 0x90, 0x71, 0x3A, + 0x0C, 0xC0, 0xC0, 0xC0, 0x0D, 0x80, 0x80, 0x80, 0x0E, 0x20, 0x20, 0x20, 0x0F, 0x00, 0x00, 0x00, }; -const BYTE SCSIPowerView::default_color_palette_16[64] = { - 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFC, 0xF3, 0x05, 0x02, 0xFF, 0x64, 0x02, 0x03, 0xDD, 0x08, 0x06, - 0x04, 0xF2, 0x08, 0x84, 0x05, 0x46, 0x00, 0xA5, 0x06, 0x00, 0x00, 0xD4, 0x07, 0x02, 0xAB, 0xEA, - 0x08, 0x1F, 0xB7, 0x14, 0x09, 0x00, 0x64, 0x11, 0x0A, 0x56, 0x2C, 0x05, 0x0B, 0x90, 0x71, 0x3A, - 0x0C, 0xC0, 0xC0, 0xC0, 0x0D, 0x80, 0x80, 0x80, 0x0E, 0x20, 0x20, 0x20, 0x0F, 0x00, 0x00, 0x00, -}; +const uint8_t SCSIPowerView::default_color_palette_256[1024] = { -const BYTE SCSIPowerView::default_color_palette_256[1024] = { - -0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xCC, 0x02, 0xFF, 0xFF, 0x99, 0x03, 0xFF, 0xFF, 0x66, -0x04, 0xFF, 0xFF, 0x33, 0x05, 0xFF, 0xFF, 0x00, 0x06, 0xFF, 0xCC, 0xFF, 0x07, 0xFF, 0xCC, 0xCC, -0x08, 0xFF, 0xCC, 0x99, 0x09, 0xFF, 0xCC, 0x66, 0x0A, 0xFF, 0xCC, 0x33, 0x0B, 0xFF, 0xCC, 0x00, -0x0C, 0xFF, 0x99, 0xFF, 0x0D, 0xFF, 0x99, 0xCC, 0x0E, 0xFF, 0x99, 0x99, 0x0F, 0xFF, 0x99, 0x66, -0x10, 0xFF, 0x99, 0x33, 0x11, 0xFF, 0x99, 0x00, 0x12, 0xFF, 0x66, 0xFF, 0x13, 0xFF, 0x66, 0xCC, -0x14, 0xFF, 0x66, 0x99, 0x15, 0xFF, 0x66, 0x66, 0x16, 0xFF, 0x66, 0x33, 0x17, 0xFF, 0x66, 0x00, -0x18, 0xFF, 0x33, 0xFF, 0x19, 0xFF, 0x33, 0xCC, 0x1A, 0xFF, 0x33, 0x99, 0x1B, 0xFF, 0x33, 0x66, -0x1C, 0xFF, 0x33, 0x33, 0x1D, 0xFF, 0x33, 0x00, 0x1E, 0xFF, 0x00, 0xFF, 0x1F, 0xFF, 0x00, 0xCC, -0x20, 0xFF, 0x00, 0x99, 0x21, 0xFF, 0x00, 0x66, 0x22, 0xFF, 0x00, 0x33, 0x23, 0xFF, 0x00, 0x00, -0x24, 0xCC, 0xFF, 0xFF, 0x25, 0xCC, 0xFF, 0xCC, 0x26, 0xCC, 0xFF, 0x99, 0x27, 0xCC, 0xFF, 0x66, -0x28, 0xCC, 0xFF, 0x33, 0x29, 0xCC, 0xFF, 0x00, 0x2A, 0xCC, 0xCC, 0xFF, 0x2B, 0xCC, 0xCC, 0xCC, -0x2C, 0xCC, 0xCC, 0x99, 0x2D, 0xCC, 0xCC, 0x66, 0x2E, 0xCC, 0xCC, 0x33, 0x2F, 0xCC, 0xCC, 0x00, -0x30, 0xCC, 0x99, 0xFF, 0x31, 0xCC, 0x99, 0xCC, 0x32, 0xCC, 0x99, 0x99, 0x33, 0xCC, 0x99, 0x66, -0x34, 0xCC, 0x99, 0x33, 0x35, 0xCC, 0x99, 0x00, 0x36, 0xCC, 0x66, 0xFF, 0x37, 0xCC, 0x66, 0xCC, -0x38, 0xCC, 0x66, 0x99, 0x39, 0xCC, 0x66, 0x66, 0x3A, 0xCC, 0x66, 0x33, 0x3B, 0xCC, 0x66, 0x00, -0x3C, 0xCC, 0x33, 0xFF, 0x3D, 0xCC, 0x33, 0xCC, 0x3E, 0xCC, 0x33, 0x99, 0x3F, 0xCC, 0x33, 0x66, -0x40, 0xCC, 0x33, 0x33, 0x41, 0xCC, 0x33, 0x00, 0x42, 0xCC, 0x00, 0xFF, 0x43, 0xCC, 0x00, 0xCC, -0x44, 0xCC, 0x00, 0x99, 0x45, 0xCC, 0x00, 0x66, 0x46, 0xCC, 0x00, 0x33, 0x47, 0xCC, 0x00, 0x00, -0x48, 0x99, 0xFF, 0xFF, 0x49, 0x99, 0xFF, 0xCC, 0x4A, 0x99, 0xFF, 0x99, 0x4B, 0x99, 0xFF, 0x66, -0x4C, 0x99, 0xFF, 0x33, 0x4D, 0x99, 0xFF, 0x00, 0x4E, 0x99, 0xCC, 0xFF, 0x4F, 0x99, 0xCC, 0xCC, -0x50, 0x99, 0xCC, 0x99, 0x51, 0x99, 0xCC, 0x66, 0x52, 0x99, 0xCC, 0x33, 0x53, 0x99, 0xCC, 0x00, -0x54, 0x99, 0x99, 0xFF, 0x55, 0x99, 0x99, 0xCC, 0x56, 0x99, 0x99, 0x99, 0x57, 0x99, 0x99, 0x66, -0x58, 0x99, 0x99, 0x33, 0x59, 0x99, 0x99, 0x00, 0x5A, 0x99, 0x66, 0xFF, 0x5B, 0x99, 0x66, 0xCC, -0x5C, 0x99, 0x66, 0x99, 0x5D, 0x99, 0x66, 0x66, 0x5E, 0x99, 0x66, 0x33, 0x5F, 0x99, 0x66, 0x00, -0x60, 0x99, 0x33, 0xFF, 0x61, 0x99, 0x33, 0xCC, 0x62, 0x99, 0x33, 0x99, 0x63, 0x99, 0x33, 0x66, -0x64, 0x99, 0x33, 0x33, 0x65, 0x99, 0x33, 0x00, 0x66, 0x99, 0x00, 0xFF, 0x67, 0x99, 0x00, 0xCC, -0x68, 0x99, 0x00, 0x99, 0x69, 0x99, 0x00, 0x66, 0x6A, 0x99, 0x00, 0x33, 0x6B, 0x99, 0x00, 0x00, -0x6C, 0x66, 0xFF, 0xFF, 0x6D, 0x66, 0xFF, 0xCC, 0x6E, 0x66, 0xFF, 0x99, 0x6F, 0x66, 0xFF, 0x66, -0x70, 0x66, 0xFF, 0x33, 0x71, 0x66, 0xFF, 0x00, 0x72, 0x66, 0xCC, 0xFF, 0x73, 0x66, 0xCC, 0xCC, -0x74, 0x66, 0xCC, 0x99, 0x75, 0x66, 0xCC, 0x66, 0x76, 0x66, 0xCC, 0x33, 0x77, 0x66, 0xCC, 0x00, -0x78, 0x66, 0x99, 0xFF, 0x79, 0x66, 0x99, 0xCC, 0x7A, 0x66, 0x99, 0x99, 0x7B, 0x66, 0x99, 0x66, -0x7C, 0x66, 0x99, 0x33, 0x7D, 0x66, 0x99, 0x00, 0x7E, 0x66, 0x66, 0xFF, 0x7F, 0x66, 0x66, 0xCC, -0x80, 0x66, 0x66, 0x99, 0x81, 0x66, 0x66, 0x66, 0x82, 0x66, 0x66, 0x33, 0x83, 0x66, 0x66, 0x00, -0x84, 0x66, 0x33, 0xFF, 0x85, 0x66, 0x33, 0xCC, 0x86, 0x66, 0x33, 0x99, 0x87, 0x66, 0x33, 0x66, -0x88, 0x66, 0x33, 0x33, 0x89, 0x66, 0x33, 0x00, 0x8A, 0x66, 0x00, 0xFF, 0x8B, 0x66, 0x00, 0xCC, -0x8C, 0x66, 0x00, 0x99, 0x8D, 0x66, 0x00, 0x66, 0x8E, 0x66, 0x00, 0x33, 0x8F, 0x66, 0x00, 0x00, -0x90, 0x33, 0xFF, 0xFF, 0x91, 0x33, 0xFF, 0xCC, 0x92, 0x33, 0xFF, 0x99, 0x93, 0x33, 0xFF, 0x66, -0x94, 0x33, 0xFF, 0x33, 0x95, 0x33, 0xFF, 0x00, 0x96, 0x33, 0xCC, 0xFF, 0x97, 0x33, 0xCC, 0xCC, -0x98, 0x33, 0xCC, 0x99, 0x99, 0x33, 0xCC, 0x66, 0x9A, 0x33, 0xCC, 0x33, 0x9B, 0x33, 0xCC, 0x00, -0x9C, 0x33, 0x99, 0xFF, 0x9D, 0x33, 0x99, 0xCC, 0x9E, 0x33, 0x99, 0x99, 0x9F, 0x33, 0x99, 0x66, -0xA0, 0x33, 0x99, 0x33, 0xA1, 0x33, 0x99, 0x00, 0xA2, 0x33, 0x66, 0xFF, 0xA3, 0x33, 0x66, 0xCC, -0xA4, 0x33, 0x66, 0x99, 0xA5, 0x33, 0x66, 0x66, 0xA6, 0x33, 0x66, 0x33, 0xA7, 0x33, 0x66, 0x00, -0xA8, 0x33, 0x33, 0xFF, 0xA9, 0x33, 0x33, 0xCC, 0xAA, 0x33, 0x33, 0x99, 0xAB, 0x33, 0x33, 0x66, -0xAC, 0x33, 0x33, 0x33, 0xAD, 0x33, 0x33, 0x00, 0xAE, 0x33, 0x00, 0xFF, 0xAF, 0x33, 0x00, 0xCC, -0xB0, 0x33, 0x00, 0x99, 0xB1, 0x33, 0x00, 0x66, 0xB2, 0x33, 0x00, 0x33, 0xB3, 0x33, 0x00, 0x00, -0xB4, 0x00, 0xFF, 0xFF, 0xB5, 0x00, 0xFF, 0xCC, 0xB6, 0x00, 0xFF, 0x99, 0xB7, 0x00, 0xFF, 0x66, -0xB8, 0x00, 0xFF, 0x33, 0xB9, 0x00, 0xFF, 0x00, 0xBA, 0x00, 0xCC, 0xFF, 0xBB, 0x00, 0xCC, 0xCC, -0xBC, 0x00, 0xCC, 0x99, 0xBD, 0x00, 0xCC, 0x66, 0xBE, 0x00, 0xCC, 0x33, 0xBF, 0x00, 0xCC, 0x00, -0xC0, 0x00, 0x99, 0xFF, 0xC1, 0x00, 0x99, 0xCC, 0xC2, 0x00, 0x99, 0x99, 0xC3, 0x00, 0x99, 0x66, -0xC4, 0x00, 0x99, 0x33, 0xC5, 0x00, 0x99, 0x00, 0xC6, 0x00, 0x66, 0xFF, 0xC7, 0x00, 0x66, 0xCC, -0xC8, 0x00, 0x66, 0x99, 0xC9, 0x00, 0x66, 0x66, 0xCA, 0x00, 0x66, 0x33, 0xCB, 0x00, 0x66, 0x00, -0xCC, 0x00, 0x33, 0xFF, 0xCD, 0x00, 0x33, 0xCC, 0xCE, 0x00, 0x33, 0x99, 0xCF, 0x00, 0x33, 0x66, -0xD0, 0x00, 0x33, 0x33, 0xD1, 0x00, 0x33, 0x00, 0xD2, 0x00, 0x00, 0xFF, 0xD3, 0x00, 0x00, 0xCC, -0xD4, 0x00, 0x00, 0x99, 0xD5, 0x00, 0x00, 0x66, 0xD6, 0x00, 0x00, 0x33, 0xD7, 0xEE, 0x00, 0x00, -0xD8, 0xDD, 0x00, 0x00, 0xD9, 0xBB, 0x00, 0x00, 0xDA, 0xAA, 0x00, 0x00, 0xDB, 0x88, 0x00, 0x00, -0xDC, 0x77, 0x00, 0x00, 0xDD, 0x55, 0x00, 0x00, 0xDE, 0x44, 0x00, 0x00, 0xDF, 0x22, 0x00, 0x00, -0xE0, 0x11, 0x00, 0x00, 0xE1, 0x00, 0xEE, 0x00, 0xE2, 0x00, 0xDD, 0x00, 0xE3, 0x00, 0xBB, 0x00, -0xE4, 0x00, 0xAA, 0x00, 0xE5, 0x00, 0x88, 0x00, 0xE6, 0x00, 0x77, 0x00, 0xE7, 0x00, 0x55, 0x00, -0xE8, 0x00, 0x44, 0x00, 0xE9, 0x00, 0x22, 0x00, 0xEA, 0x00, 0x11, 0x00, 0xEB, 0x00, 0x00, 0xEE, -0xEC, 0x00, 0x00, 0xDD, 0xED, 0x00, 0x00, 0xBB, 0xEE, 0x00, 0x00, 0xAA, 0xEF, 0x00, 0x00, 0x88, -0xF0, 0x00, 0x00, 0x77, 0xF1, 0x00, 0x00, 0x55, 0xF2, 0x00, 0x00, 0x44, 0xF3, 0x00, 0x00, 0x22, -0xF4, 0x00, 0x00, 0x11, 0xF5, 0xEE, 0xEE, 0xEE, 0xF6, 0xDD, 0xDD, 0xDD, 0xF7, 0xBB, 0xBB, 0xBB, -0xF8, 0xAA, 0xAA, 0xAA, 0xF9, 0x88, 0x88, 0x88, 0xFA, 0x77, 0x77, 0x77, 0xFB, 0x55, 0x55, 0x55, -0xFC, 0x44, 0x44, 0x44, 0xFD, 0x22, 0x22, 0x22, 0xFE, 0x11, 0x11, 0x11, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xCC, 0x02, 0xFF, 0xFF, 0x99, 0x03, 0xFF, 0xFF, 0x66, 0x04, 0xFF, 0xFF, + 0x33, 0x05, 0xFF, 0xFF, 0x00, 0x06, 0xFF, 0xCC, 0xFF, 0x07, 0xFF, 0xCC, 0xCC, 0x08, 0xFF, 0xCC, 0x99, 0x09, 0xFF, + 0xCC, 0x66, 0x0A, 0xFF, 0xCC, 0x33, 0x0B, 0xFF, 0xCC, 0x00, 0x0C, 0xFF, 0x99, 0xFF, 0x0D, 0xFF, 0x99, 0xCC, 0x0E, + 0xFF, 0x99, 0x99, 0x0F, 0xFF, 0x99, 0x66, 0x10, 0xFF, 0x99, 0x33, 0x11, 0xFF, 0x99, 0x00, 0x12, 0xFF, 0x66, 0xFF, + 0x13, 0xFF, 0x66, 0xCC, 0x14, 0xFF, 0x66, 0x99, 0x15, 0xFF, 0x66, 0x66, 0x16, 0xFF, 0x66, 0x33, 0x17, 0xFF, 0x66, + 0x00, 0x18, 0xFF, 0x33, 0xFF, 0x19, 0xFF, 0x33, 0xCC, 0x1A, 0xFF, 0x33, 0x99, 0x1B, 0xFF, 0x33, 0x66, 0x1C, 0xFF, + 0x33, 0x33, 0x1D, 0xFF, 0x33, 0x00, 0x1E, 0xFF, 0x00, 0xFF, 0x1F, 0xFF, 0x00, 0xCC, 0x20, 0xFF, 0x00, 0x99, 0x21, + 0xFF, 0x00, 0x66, 0x22, 0xFF, 0x00, 0x33, 0x23, 0xFF, 0x00, 0x00, 0x24, 0xCC, 0xFF, 0xFF, 0x25, 0xCC, 0xFF, 0xCC, + 0x26, 0xCC, 0xFF, 0x99, 0x27, 0xCC, 0xFF, 0x66, 0x28, 0xCC, 0xFF, 0x33, 0x29, 0xCC, 0xFF, 0x00, 0x2A, 0xCC, 0xCC, + 0xFF, 0x2B, 0xCC, 0xCC, 0xCC, 0x2C, 0xCC, 0xCC, 0x99, 0x2D, 0xCC, 0xCC, 0x66, 0x2E, 0xCC, 0xCC, 0x33, 0x2F, 0xCC, + 0xCC, 0x00, 0x30, 0xCC, 0x99, 0xFF, 0x31, 0xCC, 0x99, 0xCC, 0x32, 0xCC, 0x99, 0x99, 0x33, 0xCC, 0x99, 0x66, 0x34, + 0xCC, 0x99, 0x33, 0x35, 0xCC, 0x99, 0x00, 0x36, 0xCC, 0x66, 0xFF, 0x37, 0xCC, 0x66, 0xCC, 0x38, 0xCC, 0x66, 0x99, + 0x39, 0xCC, 0x66, 0x66, 0x3A, 0xCC, 0x66, 0x33, 0x3B, 0xCC, 0x66, 0x00, 0x3C, 0xCC, 0x33, 0xFF, 0x3D, 0xCC, 0x33, + 0xCC, 0x3E, 0xCC, 0x33, 0x99, 0x3F, 0xCC, 0x33, 0x66, 0x40, 0xCC, 0x33, 0x33, 0x41, 0xCC, 0x33, 0x00, 0x42, 0xCC, + 0x00, 0xFF, 0x43, 0xCC, 0x00, 0xCC, 0x44, 0xCC, 0x00, 0x99, 0x45, 0xCC, 0x00, 0x66, 0x46, 0xCC, 0x00, 0x33, 0x47, + 0xCC, 0x00, 0x00, 0x48, 0x99, 0xFF, 0xFF, 0x49, 0x99, 0xFF, 0xCC, 0x4A, 0x99, 0xFF, 0x99, 0x4B, 0x99, 0xFF, 0x66, + 0x4C, 0x99, 0xFF, 0x33, 0x4D, 0x99, 0xFF, 0x00, 0x4E, 0x99, 0xCC, 0xFF, 0x4F, 0x99, 0xCC, 0xCC, 0x50, 0x99, 0xCC, + 0x99, 0x51, 0x99, 0xCC, 0x66, 0x52, 0x99, 0xCC, 0x33, 0x53, 0x99, 0xCC, 0x00, 0x54, 0x99, 0x99, 0xFF, 0x55, 0x99, + 0x99, 0xCC, 0x56, 0x99, 0x99, 0x99, 0x57, 0x99, 0x99, 0x66, 0x58, 0x99, 0x99, 0x33, 0x59, 0x99, 0x99, 0x00, 0x5A, + 0x99, 0x66, 0xFF, 0x5B, 0x99, 0x66, 0xCC, 0x5C, 0x99, 0x66, 0x99, 0x5D, 0x99, 0x66, 0x66, 0x5E, 0x99, 0x66, 0x33, + 0x5F, 0x99, 0x66, 0x00, 0x60, 0x99, 0x33, 0xFF, 0x61, 0x99, 0x33, 0xCC, 0x62, 0x99, 0x33, 0x99, 0x63, 0x99, 0x33, + 0x66, 0x64, 0x99, 0x33, 0x33, 0x65, 0x99, 0x33, 0x00, 0x66, 0x99, 0x00, 0xFF, 0x67, 0x99, 0x00, 0xCC, 0x68, 0x99, + 0x00, 0x99, 0x69, 0x99, 0x00, 0x66, 0x6A, 0x99, 0x00, 0x33, 0x6B, 0x99, 0x00, 0x00, 0x6C, 0x66, 0xFF, 0xFF, 0x6D, + 0x66, 0xFF, 0xCC, 0x6E, 0x66, 0xFF, 0x99, 0x6F, 0x66, 0xFF, 0x66, 0x70, 0x66, 0xFF, 0x33, 0x71, 0x66, 0xFF, 0x00, + 0x72, 0x66, 0xCC, 0xFF, 0x73, 0x66, 0xCC, 0xCC, 0x74, 0x66, 0xCC, 0x99, 0x75, 0x66, 0xCC, 0x66, 0x76, 0x66, 0xCC, + 0x33, 0x77, 0x66, 0xCC, 0x00, 0x78, 0x66, 0x99, 0xFF, 0x79, 0x66, 0x99, 0xCC, 0x7A, 0x66, 0x99, 0x99, 0x7B, 0x66, + 0x99, 0x66, 0x7C, 0x66, 0x99, 0x33, 0x7D, 0x66, 0x99, 0x00, 0x7E, 0x66, 0x66, 0xFF, 0x7F, 0x66, 0x66, 0xCC, 0x80, + 0x66, 0x66, 0x99, 0x81, 0x66, 0x66, 0x66, 0x82, 0x66, 0x66, 0x33, 0x83, 0x66, 0x66, 0x00, 0x84, 0x66, 0x33, 0xFF, + 0x85, 0x66, 0x33, 0xCC, 0x86, 0x66, 0x33, 0x99, 0x87, 0x66, 0x33, 0x66, 0x88, 0x66, 0x33, 0x33, 0x89, 0x66, 0x33, + 0x00, 0x8A, 0x66, 0x00, 0xFF, 0x8B, 0x66, 0x00, 0xCC, 0x8C, 0x66, 0x00, 0x99, 0x8D, 0x66, 0x00, 0x66, 0x8E, 0x66, + 0x00, 0x33, 0x8F, 0x66, 0x00, 0x00, 0x90, 0x33, 0xFF, 0xFF, 0x91, 0x33, 0xFF, 0xCC, 0x92, 0x33, 0xFF, 0x99, 0x93, + 0x33, 0xFF, 0x66, 0x94, 0x33, 0xFF, 0x33, 0x95, 0x33, 0xFF, 0x00, 0x96, 0x33, 0xCC, 0xFF, 0x97, 0x33, 0xCC, 0xCC, + 0x98, 0x33, 0xCC, 0x99, 0x99, 0x33, 0xCC, 0x66, 0x9A, 0x33, 0xCC, 0x33, 0x9B, 0x33, 0xCC, 0x00, 0x9C, 0x33, 0x99, + 0xFF, 0x9D, 0x33, 0x99, 0xCC, 0x9E, 0x33, 0x99, 0x99, 0x9F, 0x33, 0x99, 0x66, 0xA0, 0x33, 0x99, 0x33, 0xA1, 0x33, + 0x99, 0x00, 0xA2, 0x33, 0x66, 0xFF, 0xA3, 0x33, 0x66, 0xCC, 0xA4, 0x33, 0x66, 0x99, 0xA5, 0x33, 0x66, 0x66, 0xA6, + 0x33, 0x66, 0x33, 0xA7, 0x33, 0x66, 0x00, 0xA8, 0x33, 0x33, 0xFF, 0xA9, 0x33, 0x33, 0xCC, 0xAA, 0x33, 0x33, 0x99, + 0xAB, 0x33, 0x33, 0x66, 0xAC, 0x33, 0x33, 0x33, 0xAD, 0x33, 0x33, 0x00, 0xAE, 0x33, 0x00, 0xFF, 0xAF, 0x33, 0x00, + 0xCC, 0xB0, 0x33, 0x00, 0x99, 0xB1, 0x33, 0x00, 0x66, 0xB2, 0x33, 0x00, 0x33, 0xB3, 0x33, 0x00, 0x00, 0xB4, 0x00, + 0xFF, 0xFF, 0xB5, 0x00, 0xFF, 0xCC, 0xB6, 0x00, 0xFF, 0x99, 0xB7, 0x00, 0xFF, 0x66, 0xB8, 0x00, 0xFF, 0x33, 0xB9, + 0x00, 0xFF, 0x00, 0xBA, 0x00, 0xCC, 0xFF, 0xBB, 0x00, 0xCC, 0xCC, 0xBC, 0x00, 0xCC, 0x99, 0xBD, 0x00, 0xCC, 0x66, + 0xBE, 0x00, 0xCC, 0x33, 0xBF, 0x00, 0xCC, 0x00, 0xC0, 0x00, 0x99, 0xFF, 0xC1, 0x00, 0x99, 0xCC, 0xC2, 0x00, 0x99, + 0x99, 0xC3, 0x00, 0x99, 0x66, 0xC4, 0x00, 0x99, 0x33, 0xC5, 0x00, 0x99, 0x00, 0xC6, 0x00, 0x66, 0xFF, 0xC7, 0x00, + 0x66, 0xCC, 0xC8, 0x00, 0x66, 0x99, 0xC9, 0x00, 0x66, 0x66, 0xCA, 0x00, 0x66, 0x33, 0xCB, 0x00, 0x66, 0x00, 0xCC, + 0x00, 0x33, 0xFF, 0xCD, 0x00, 0x33, 0xCC, 0xCE, 0x00, 0x33, 0x99, 0xCF, 0x00, 0x33, 0x66, 0xD0, 0x00, 0x33, 0x33, + 0xD1, 0x00, 0x33, 0x00, 0xD2, 0x00, 0x00, 0xFF, 0xD3, 0x00, 0x00, 0xCC, 0xD4, 0x00, 0x00, 0x99, 0xD5, 0x00, 0x00, + 0x66, 0xD6, 0x00, 0x00, 0x33, 0xD7, 0xEE, 0x00, 0x00, 0xD8, 0xDD, 0x00, 0x00, 0xD9, 0xBB, 0x00, 0x00, 0xDA, 0xAA, + 0x00, 0x00, 0xDB, 0x88, 0x00, 0x00, 0xDC, 0x77, 0x00, 0x00, 0xDD, 0x55, 0x00, 0x00, 0xDE, 0x44, 0x00, 0x00, 0xDF, + 0x22, 0x00, 0x00, 0xE0, 0x11, 0x00, 0x00, 0xE1, 0x00, 0xEE, 0x00, 0xE2, 0x00, 0xDD, 0x00, 0xE3, 0x00, 0xBB, 0x00, + 0xE4, 0x00, 0xAA, 0x00, 0xE5, 0x00, 0x88, 0x00, 0xE6, 0x00, 0x77, 0x00, 0xE7, 0x00, 0x55, 0x00, 0xE8, 0x00, 0x44, + 0x00, 0xE9, 0x00, 0x22, 0x00, 0xEA, 0x00, 0x11, 0x00, 0xEB, 0x00, 0x00, 0xEE, 0xEC, 0x00, 0x00, 0xDD, 0xED, 0x00, + 0x00, 0xBB, 0xEE, 0x00, 0x00, 0xAA, 0xEF, 0x00, 0x00, 0x88, 0xF0, 0x00, 0x00, 0x77, 0xF1, 0x00, 0x00, 0x55, 0xF2, + 0x00, 0x00, 0x44, 0xF3, 0x00, 0x00, 0x22, 0xF4, 0x00, 0x00, 0x11, 0xF5, 0xEE, 0xEE, 0xEE, 0xF6, 0xDD, 0xDD, 0xDD, + 0xF7, 0xBB, 0xBB, 0xBB, 0xF8, 0xAA, 0xAA, 0xAA, 0xF9, 0x88, 0x88, 0x88, 0xFA, 0x77, 0x77, 0x77, 0xFB, 0x55, 0x55, + 0x55, 0xFC, 0x44, 0x44, 0x44, 0xFD, 0x22, 0x22, 0x22, 0xFE, 0x11, 0x11, 0x11, 0xFF, 0x00, 0x00, 0x00, }; \ No newline at end of file diff --git a/cpp/piscsi_interface.proto b/cpp/piscsi_interface.proto index d99ead12..2204e164 100644 --- a/cpp/piscsi_interface.proto +++ b/cpp/piscsi_interface.proto @@ -41,6 +41,8 @@ enum PbDeviceType { SCHS = 8; // Printer device SCLP = 9; + // PowerView device + SCPV = 10; } // piscsi remote operations, returning PbResult diff --git a/cpp/rebuild.sh b/cpp/rebuild.sh index dfafb2ca..30657476 100755 --- a/cpp/rebuild.sh +++ b/cpp/rebuild.sh @@ -1,12 +1,12 @@ make all -j4 DEBUG=1 -sudo systemctl stop rascsi +sudo systemctl stop piscsi sudo make install -sudo systemctl start rascsi +sudo systemctl start piscsi sleep 1 rasctl -c attach -i 4 -f powerview #rasctl -c attach -i 0 -f /home/pi/images/RaSCSI-BootstrapV3.hda #rasctl -c attach -i 0 -f /home/pi/images/claris_works.hda rasctl -l -tail -f /var/log/rascsi.log +tail -f /var/log/piscsi.log diff --git a/cpp/shared/scsi.h b/cpp/shared/scsi.h index 8ebccc8d..ec3a2445 100644 --- a/cpp/shared/scsi.h +++ b/cpp/shared/scsi.h @@ -179,5 +179,11 @@ static const unordered_map> command_mapping {scsi_command::eCmdSynchronizeCache16, make_pair(16, "SynchronizeCache16")}, {scsi_command::eCmdReadCapacity16_ReadLong16, make_pair(16, "ReadCapacity16/ReadLong16")}, {scsi_command::eCmdWriteLong16, make_pair(16, "WriteLong16")}, - {scsi_command::eCmdReportLuns, make_pair(12, "ReportLuns")}}; + {scsi_command::eCmdReportLuns, make_pair(12, "ReportLuns")}, + {scsi_command::eCmdPvReadConfig, make_pair(6, "eCmdPvReadConfig")}, + {scsi_command::eCmdPvWriteConfig, make_pair(6, "eCmdPvWriteConfig")}, + {scsi_command::eCmdPvWriteFrameBuffer, make_pair(6, "eCmdPvWriteFrameBuffer")}, + {scsi_command::eCmdPvWriteColorPalette, make_pair(6, "eCmdPvWriteColorPalette")}, + {scsi_command::eCmdUnknownPowerViewCC, make_pair(6, "eCmdUnknownPowerViewCC")}}; + }; // namespace scsi_defs