diff --git a/src/raspberrypi/.vscode/settings.json b/src/raspberrypi/.vscode/settings.json index 9dd7c2c5..f04eecef 100644 --- a/src/raspberrypi/.vscode/settings.json +++ b/src/raspberrypi/.vscode/settings.json @@ -11,6 +11,9 @@ "type_traits": "cpp", "utility": "cpp", "string_view": "cpp", - "regex": "cpp" + "regex": "cpp", + "*.tcc": "cpp", + "numeric": "cpp", + "sstream": "cpp" } } \ No newline at end of file diff --git a/src/raspberrypi/controllers/sasidev_ctrl.cpp b/src/raspberrypi/controllers/sasidev_ctrl.cpp index 7e613584..c45943ec 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.cpp +++ b/src/raspberrypi/controllers/sasidev_ctrl.cpp @@ -18,6 +18,7 @@ #include "gpiobus.h" #include "devices/scsi_host_bridge.h" #include "devices/scsi_daynaport.h" +#include "devices/scsi_powerview.h" #include //=========================================================================== @@ -1201,12 +1202,43 @@ bool SASIDEV::XferOut(bool cont) case SASIDEV::eCmdInvalid: break; + case SASIDEV::eCmdWriteFrameBuffer: + LOGDEBUG("Writing Frame Buffer ($%02X) in %s. Length: %08X (%d)", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__, ctrl.offset, ctrl.offset); + LOGDEBUG(" %02X%02X%02X%02X %02X%02X%02X%02X", ctrl.buffer[0],ctrl.buffer[1],ctrl.buffer[2],ctrl.buffer[3],ctrl.buffer[4],ctrl.buffer[5],ctrl.buffer[6],ctrl.buffer[7]); + + if (device->IsPowerView()) { + if (!((SCSIPowerView*)device)->WriteFrameBuffer(ctrl.cmd, ctrl.buffer, ctrl.offset)) { + // write failed + return false; + } + + // If normal, work setting + ctrl.offset = 0; + break; + } + + return true; + break; + + case SASIDEV::eCmdUnknownPowerViewC8: case SASIDEV::eCmdUnknownPowerViewC9: - case SASIDEV::eCmdUnknownPowerViewCA: case SASIDEV::eCmdUnknownPowerViewCB: case SASIDEV::eCmdUnknownPowerViewCC: - LOGWARN("Finished receiving a Powerview Command ($%02X) in %s. Length: %08X (%d)", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__, ctrl.length, ctrl.length); + LOGDEBUG("Finished receiving a Powerview Command ($%02X) in %s. Length: %08X (%d)", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__, ctrl.offset, ctrl.offset); + LOGDEBUG(" %02X%02X%02X%02X %02X%02X%02X%02X", ctrl.buffer[0],ctrl.buffer[1],ctrl.buffer[2],ctrl.buffer[3],ctrl.buffer[4],ctrl.buffer[5],ctrl.buffer[6],ctrl.buffer[7]); + + if (device->IsPowerView()) { + if (!((SCSIPowerView*)device)->Write(ctrl.cmd, ctrl.buffer, ctrl.offset)) { + // write failed + return false; + } + + // If normal, work setting + ctrl.offset = 0; + break; + } + return true; break; case SASIDEV::eCmdSetMcastAddr: @@ -1272,6 +1304,14 @@ void SASIDEV::FlushUnit() } break; + case SASIDEV::eCmdUnknownPowerViewC8: + case SASIDEV::eCmdUnknownPowerViewC9: + case SASIDEV::eCmdWriteFrameBuffer: + case SASIDEV::eCmdUnknownPowerViewCB: + case SASIDEV::eCmdUnknownPowerViewCC: + LOGDEBUG("%s Received PowerView flush %02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]); + break; + case SASIDEV::eCmdSetMcastAddr: // TODO: Eventually, we should store off the multicast address configuration data here... break; diff --git a/src/raspberrypi/controllers/sasidev_ctrl.h b/src/raspberrypi/controllers/sasidev_ctrl.h index 8a5f16ca..43aa5fa1 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.h +++ b/src/raspberrypi/controllers/sasidev_ctrl.h @@ -83,7 +83,7 @@ private: eCmdSasiCmdAssign = 0x0E, eCmdUnknownPowerViewC8 = 0xC8, eCmdUnknownPowerViewC9 = 0xC9, - eCmdUnknownPowerViewCA = 0xCA, + eCmdWriteFrameBuffer = 0xCA, eCmdUnknownPowerViewCB = 0xCB, eCmdUnknownPowerViewCC = 0xCC }; @@ -95,8 +95,6 @@ public: const int UNKNOWN_SCSI_ID = -1; const int DEFAULT_BUFFER_SIZE = 0x1000; - // TODO Remove this duplicate - const int DAYNAPORT_BUFFER_SIZE = 0x1000000; // For timing adjustments enum { diff --git a/src/raspberrypi/controllers/scsidev_ctrl.h b/src/raspberrypi/controllers/scsidev_ctrl.h index 5a8e0ca1..5668bd25 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.h +++ b/src/raspberrypi/controllers/scsidev_ctrl.h @@ -72,7 +72,7 @@ public: eCmdReportLuns = 0xA0, eCmdUnknownPowerViewC8 = 0xC8, eCmdUnknownPowerViewC9 = 0xC9, - eCmdUnknownPowerViewCA = 0xCA, + eCmdWriteFrameBuffer = 0xCA, eCmdUnknownPowerViewCB = 0xCB, eCmdUnknownPowerViewCC = 0xCC, }; diff --git a/src/raspberrypi/devices/device.h b/src/raspberrypi/devices/device.h index f08372a9..2a741fbf 100644 --- a/src/raspberrypi/devices/device.h +++ b/src/raspberrypi/devices/device.h @@ -182,4 +182,5 @@ public: bool IsMo() const { return type == "SCMO"; } bool IsBridge() const { return type == "SCBR"; } bool IsDaynaPort() const { return type == "SCDP"; } + bool IsPowerView() const { return type == "SCPV"; } }; diff --git a/src/raspberrypi/devices/scsi_powerview.cpp b/src/raspberrypi/devices/scsi_powerview.cpp index d97098e1..cb4b3c06 100644 --- a/src/raspberrypi/devices/scsi_powerview.cpp +++ b/src/raspberrypi/devices/scsi_powerview.cpp @@ -3,34 +3,25 @@ // SCSI Target Emulator RaSCSI (*^..^*) // for Raspberry Pi // -// Copyright (C) 2020 akuker -// Copyright (C) 2014-2020 GIMONS -// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2020-2021 akuker +// Copyright (C) 2020 joshua stein // // Licensed under the BSD 3-Clause License. // See LICENSE file in the project root folder. // -// [ Emulation of the DaynaPort SCSI Link Ethernet interface ] +// [ Emulation of the Radius PowerView SCSI Display Adapter ] // -// This design is derived from the SLINKCMD.TXT file, as well as David Kuder's -// Tiny SCSI Emulator -// - SLINKCMD: http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/SLINKCMD.TXT -// - Tiny SCSI : https://hackaday.io/project/18974-tiny-scsi-emulator +// Note: This requires the Radius RadiusWare driver. // -// Additional documentation and clarification is available at the -// following link: -// - https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link +// Framebuffer integration originally done by Joshua Stein: +// https://github.com/jcs/RASCSI/commit/6da9e9f3ffcd38eb89413cd445f7407739c54bca // -// This does NOT include the file system functionality that is present -// in the Sharp X68000 host bridge. -// -// Note: This requires a DaynaPort SCSI Link driver. //--------------------------------------------------------------------------- #include "scsi_powerview.h" #include - +#include "exceptions.h" #include #include #include @@ -41,9 +32,6 @@ static unsigned char reverse_table[256]; -// const BYTE SCSIPowerView::m_bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -// const BYTE SCSIPowerView::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff }; - 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, @@ -56,7 +44,7 @@ SCSIPowerView::SCSIPowerView() : Disk("SCPV") { AddCommand(SCSIDEV::eCmdUnknownPowerViewC8, "Unknown PowerViewC8", &SCSIPowerView::UnknownCommandC8); AddCommand(SCSIDEV::eCmdUnknownPowerViewC9, "Unknown PowerViewC9", &SCSIPowerView::UnknownCommandC9); - AddCommand(SCSIDEV::eCmdUnknownPowerViewCA, "Unknown PowerViewCA", &SCSIPowerView::UnknownCommandCA); + AddCommand(SCSIDEV::eCmdWriteFrameBuffer, "Unknown PowerViewCA", &SCSIPowerView::CmdWriteFramebuffer); AddCommand(SCSIDEV::eCmdUnknownPowerViewCB, "Unknown PowerViewCB", &SCSIPowerView::UnknownCommandCB); AddCommand(SCSIDEV::eCmdUnknownPowerViewCC, "Unknown PowerViewCC", &SCSIPowerView::UnknownCommandCC); @@ -72,9 +60,13 @@ SCSIPowerView::SCSIPowerView() : Disk("SCPV") reverse_table[i] = b; } + for(int i=0; i < (256/8); i++){ + LOGINFO("%02X %02X %02X %02X %02X %02X %02X %02X ", reverse_table[(i*8)],reverse_table[(i*8)+1],reverse_table[(i*8)+2],reverse_table[(i*8)+3], reverse_table[(i*8)+4], reverse_table[(i*8)+5], reverse_table[(i*8)+6], reverse_table[(i*7)] ); + } + // TODO: receive these through a SCSI message sent by the remote - this->screen_width = 512; - this->screen_height = 342; + this->screen_width = 624; + this->screen_height = 840; this->fbfd = open("/dev/fb0", O_RDWR); if (this->fbfd == -1) @@ -95,7 +87,7 @@ SCSIPowerView::SCSIPowerView() : Disk("SCPV") this->fblinelen = fbfixinfo.line_length; this->fbsize = fbfixinfo.smem_len; - printf("SCSIVideo drawing on %dx%d %d bpp framebuffer\n", + LOGWARN("SCSIVideo drawing on %dx%d %d bpp framebuffer\n", this->fbwidth, this->fbheight, this->fbbpp); this->fb = (char *)mmap(0, this->fbsize, PROT_READ | PROT_WRITE, MAP_SHARED, @@ -105,6 +97,9 @@ SCSIPowerView::SCSIPowerView() : Disk("SCPV") memset(this->fb, 0, this->fbsize); + this->m_powerview_resolution_x = 624; + this->m_powerview_resolution_y = 840; + } SCSIPowerView::~SCSIPowerView() @@ -218,11 +213,16 @@ void SCSIPowerView::UnknownCommandC9(SASIDEV *controller) // Unknown Command CA // //--------------------------------------------------------------------------- -void SCSIPowerView::UnknownCommandCA(SASIDEV *controller) +void SCSIPowerView::CmdWriteFramebuffer(SASIDEV *controller) { + // 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); + } // Set transfer amount - // ctrl->length = ctrl->cmd[6]; uint16_t width_x = ctrl->cmd[5] + (ctrl->cmd[4] << 8); uint16_t height_y = ctrl->cmd[7] + (ctrl->cmd[6] << 8); @@ -233,7 +233,7 @@ void SCSIPowerView::UnknownCommandCA(SASIDEV *controller) // else { // ctrl->length = ctrl->cmd[7] * 2; // } - LOGWARN("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); + LOGWARN("%s Message Length %d [%08X]", __PRETTY_FUNCTION__, (int)ctrl->length, (unsigned int)ctrl->length); LOGWARN(" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X [%02X %02X]\n", ctrl->cmd[0], ctrl->cmd[1], @@ -341,48 +341,12 @@ bool SCSIPowerView::Init(const map& params) { SetParams(params.empty() ? GetDefaultParams() : params); -// #ifdef __linux__ -// // TAP Driver Generation -// m_tap = new CTapDriver(GetParam("interfaces")); -// m_bTapEnable = m_tap->Init(); -// if(!m_bTapEnable){ -// LOGERROR("Unable to open the TAP interface"); - -// // Not terminating on regular Linux PCs is helpful for testing -// #if !defined(__x86_64__) && !defined(__X86__) -// return false; -// #endif -// } else { -// LOGDEBUG("Tap interface created"); -// } - -// this->Reset(); -// SetReady(true); -// SetReset(false); - -// // Generate MAC Address -// memset(m_mac_addr, 0x00, 6); - -// // if (m_bTapEnable) { -// // tap->GetMacAddr(m_mac_addr); -// // m_mac_addr[5]++; -// // } -// // !!!!!!!!!!!!!!!!! For now, hard code the MAC address. Its annoying when it keeps changing during development! -// // TODO: Remove this hard-coded address -// m_mac_addr[0]=0x00; -// m_mac_addr[1]=0x80; -// m_mac_addr[2]=0x19; -// m_mac_addr[3]=0x10; -// m_mac_addr[4]=0x98; -// m_mac_addr[5]=0xE3; -// #endif // linux - return true; } void SCSIPowerView::Open(const Filepath& path) { - // m_tap->OpenDump(path); + } //--------------------------------------------------------------------------- @@ -423,56 +387,6 @@ int SCSIPowerView::Inquiry(const DWORD *cdb, BYTE *buf) -// //--------------------------------------------------------------------------- -// // -// // INQUIRY -// // -// //--------------------------------------------------------------------------- -// int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf) -// { -// ASSERT(cdb); -// ASSERT(buf); - -// // EVPD check -// if (cdb[1] & 0x01) { -// SetStatusCode(STATUS_INVALIDCDB); -// return 0; -// } - -// // Ready check (Error if no image file) -// if (!IsReady()) { -// SetStatusCode(STATUS_NOTREADY); -// return 0; -// } - -// // Basic data -// // buf[0] ... Direct Access Device -// // buf[1] ... Bit 7 set means removable -// // buf[2] ... SCSI-2 compliant command system -// // buf[3] ... SCSI-2 compliant Inquiry response -// // buf[4] ... Inquiry additional data -// memset(buf, 0, 8); -// buf[1] = IsRemovable() ? 0x80 : 0x00; -// buf[2] = 0x02; -// buf[3] = 0x02; -// buf[4] = 28 + 3; // Value close to real HDD - -// // Padded vendor, product, revision -// memcpy(&buf[8], GetPaddedName().c_str(), 28); - -// // Size of data that can be returned -// int size = (buf[4] + 5); - -// // Limit if the other buffer is small -// if (size > (int)cdb[4]) { -// size = (int)cdb[4]; -// } - -// return size; -// } - - - //--------------------------------------------------------------------------- // @@ -509,145 +423,124 @@ int SCSIPowerView::Read(const DWORD *cdb, BYTE *buf, uint64_t block) { int rx_packet_size = 0; return rx_packet_size; - // scsi_resp_read_t *response = (scsi_resp_read_t*)buf; - // ostringstream s; - // s << __PRETTY_FUNCTION__ << " reading DaynaPort block " << block; - // LOGTRACE("%s", s.str().c_str()); - - // int requested_length = cdb[4]; - // LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length); - - - // // At host startup, it will send a READ(6) command with a length of 1. We should - // // respond by going into the status mode with a code of 0x02 - // if (requested_length == 1) { - // return 0; - // } - - // // Some of the packets we receive will not be for us. So, we'll keep pulling messages - // // until the buffer is empty, or we've read X times. (X is just a made up number) - // bool send_message_to_host; - // int read_count = 0; - // while (read_count < MAX_READ_RETRIES) { - // read_count++; - - // // The first 2 bytes are reserved for the length of the packet - // // The next 4 bytes are reserved for a flag field - // //rx_packet_size = m_tap->Rx(response->data); - // rx_packet_size = m_tap->Rx(&buf[DAYNAPORT_READ_HEADER_SZ]); - - // // If we didn't receive anything, return size of 0 - // if (rx_packet_size <= 0) { - // LOGTRACE("%s No packet received", __PRETTY_FUNCTION__); - // response->length = 0; - // response->flags = e_no_more_data; - // return DAYNAPORT_READ_HEADER_SZ; - // } - - // LOGTRACE("%s Packet Sz %d (%08X) read: %d", __PRETTY_FUNCTION__, (unsigned int) rx_packet_size, (unsigned int) rx_packet_size, read_count); - - // // This is a very basic filter to prevent unnecessary packets from - // // being sent to the SCSI initiator. - // send_message_to_host = false; - - // // The following doesn't seem to work with unicast messages. Temporarily removing the filtering - // // functionality. - // /////// // Check if received packet destination MAC address matches the - // /////// // DaynaPort MAC. For IP packets, the mac_address will be the first 6 bytes - // /////// // of the data. - // /////// if (memcmp(response->data, m_mac_addr, 6) == 0) { - // /////// send_message_to_host = true; - // /////// } - - // /////// // Check to see if this is a broadcast message - // /////// if (memcmp(response->data, m_bcast_addr, 6) == 0) { - // /////// send_message_to_host = true; - // /////// } - - // /////// // Check to see if this is an AppleTalk Message - // /////// if (memcmp(response->data, m_apple_talk_addr, 6) == 0) { - // /////// send_message_to_host = true; - // /////// } - // send_message_to_host = true; - - // // TODO: We should check to see if this message is in the multicast - // // configuration from SCSI command 0x0D - - // if (!send_message_to_host) { - // LOGDEBUG("%s Received a packet that's not for me: %02X %02X %02X %02X %02X %02X", - // __PRETTY_FUNCTION__, - // (int)response->data[0], - // (int)response->data[1], - // (int)response->data[2], - // (int)response->data[3], - // (int)response->data[4], - // (int)response->data[5]); - - // // If there are pending packets to be processed, we'll tell the host that the read - // // length was 0. - // if (!m_tap->PendingPackets()) - // { - // response->length = 0; - // response->flags = e_no_more_data; - // return DAYNAPORT_READ_HEADER_SZ; - // } - // } - // else { - // // TODO: Need to do some sort of size checking. The buffer can easily overflow, probably. - - // // response->length = rx_packet_size; - // // if(m_tap->PendingPackets()){ - // // response->flags = e_more_data_available; - // // } else { - // // response->flags = e_no_more_data; - // // } - // buf[0] = (BYTE)((rx_packet_size >> 8) & 0xFF); - // buf[1] = (BYTE)(rx_packet_size & 0xFF); - - // buf[2] = 0; - // buf[3] = 0; - // buf[4] = 0; - // if(m_tap->PendingPackets()){ - // buf[5] = 0x10; - // } else { - // buf[5] = 0; - // } - - // // Return the packet size + 2 for the length + 4 for the flag field - // // The CRC was already appended by the ctapdriver - // return rx_packet_size + DAYNAPORT_READ_HEADER_SZ; - // } - // // If we got to this point, there are still messages in the queue, so - // // we should loop back and get the next one. - // } // end while - - // response->length = 0; - // response->flags = e_no_more_data; - // return DAYNAPORT_READ_HEADER_SZ; } -// //--------------------------------------------------------------------------- -// // -// // WRITE check -// // -// //--------------------------------------------------------------------------- -// int SCSIPowerView::WriteCheck(DWORD block) -// { -// // // Status check -// // if (!CheckReady()) { -// // return 0; -// // } -// // if (!m_bTapEnable){ -// // SetStatusCode(STATUS_NOTREADY); -// // return 0; -// // } +bool SCSIPowerView::WriteFrameBuffer(const DWORD *cdb, const BYTE *buf, const DWORD length) +{ + + + // try { + + // Apple portrait display resolution + // 624 by 840 + + // const int bits_per_pixel = 1; + + // BYTE pixel_value = 0; + + + // this->screen_width = 624; + // this->screen_height = 840; + + // // TODO: receive these through a SCSI message sent by the remote + // this->screen_width = 624; + // this->screen_height = 840; + + // 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); + + LOGDEBUG("%s act length %ul offset:%06X (%f) wid:%06X height:%06X", __PRETTY_FUNCTION__, length, offset, ((float)offset/(screen_width*screen_height)), update_width_x_bytes, update_height_y_bytes); + + uint32_t offset_row = (uint32_t)((offset*8) / this->screen_width)/2; + uint32_t offset_col = (uint32_t)((offset*8) % this->screen_width); + + LOGDEBUG("WriteFrameBuffer: Update x:%06X y:%06X width:%06X height:%06X", offset_col, offset_row, update_width_x_bytes * 8, update_height_y_bytes ) + + + // For each row + for (DWORD idx_row_y = 0; idx_row_y < (update_height_y_bytes); idx_row_y++){ + + + // For each column + for (DWORD idx_col_x = 0; idx_col_x < (update_width_x_bytes*8); idx_col_x++){ + + DWORD pixel_byte_idx = (idx_row_y * update_width_x_bytes) + (idx_col_x / 8); + BYTE pixel_byte = reverse_table[buf[pixel_byte_idx]]; + // BYTE pixel_byte =buf[pixel_byte_idx]; + DWORD pixel_bit = idx_col_x % 8; + + BYTE pixel = (pixel_byte & (1 << pixel_bit) ? 255 : 0); + + // int loc = (col * (this->fbbpp / 8)) + (row * this->fblinelen); + uint32_t loc = ((idx_col_x + offset_col) * (this->fbbpp / 8)) + ((idx_row_y + offset_row) * fblinelen); + + // LOGDEBUG("!!! x:%d y:%d !! pix_idx:%06X pix_byte:%04X pix_bit:%02X pixel: %02X, loc:%08X",idx_col_x, idx_row_y, pixel_byte_idx, pixel_byte, pixel_bit, pixel, loc); + + for(int i=0 ; i< (this->fbbpp/8); i++){ + *(this->fb + loc + i) = pixel; + } + } + } + + + // LOGWARN("%s start row: %06X col: %06X", __PRETTY_FUNCTION__, (unsigned int)offset_row, (unsigned int)offset_col); + + // for (DWORD pixel_x = offset_col; pixel_x < (offset_col + (update_width_x_bytes * 8)); offset_col++){ + // for (DWORD pixel_y = offset_row; pixel_y < offset_row + (update_height_y_bytes); offset_row++){ + + // BYTE pixel_byte = (pixel_y * update_height_y_bytes) + (pixel_x/8); + // int pixel_bit = (pixel_x % 8); + // pixel_value = ((buf[pixel_byte]) << pixel_bit) != 0; + + // int loc = (pixel_x * (this->fbbpp / 8)) + (pixel_y * m_powerview_resolution_x); + + // // int idx = (pixel_y * update_width_x_bytes * 8); + // // pixel_value = buf[] + + // *(this->fb + loc) = (pixel_bit) ? 0 : 255; + // *(this->fb + loc + 1) = (pixel_bit) ? 0 : 255; + // // *(this->fb + loc + 2) = (j & (1 << bit)) ? 0 : 255; + + + // } + + + // } + + + + + // for (DWORD i = 0; i < length; i++) { + // unsigned char j = reverse_table[buf[i]]; + + // for (int bit = 0; bit < 8; bit++) { + // int loc = (offset_col * (this->fbbpp / 8)) + (offset_row * this->fblinelen); + // offset_col++; + // // if (col % this->screen_width == 0) { + // if (offset_col % update_width_x == 0) { + // offset_col = 0; + // offset_row++; + // } + + // *(this->fb + loc) = (j & (1 << bit)) ? 0 : 255; + // *(this->fb + loc + 1) = (j & (1 << bit)) ? 0 : 255; + // *(this->fb + loc + 2) = (j & (1 << bit)) ? 0 : 255; + // } + // } + // } + + // catch(const exception& e) { + // LOGWARN("Exception!!!!!!!!!"); + // } + + return true; +} -// // Success -// return 1; -// } - //--------------------------------------------------------------------------- // // Write @@ -666,7 +559,7 @@ int SCSIPowerView::Read(const DWORD *cdb, BYTE *buf, uint64_t block) // XX XX ... is the actual packet // //--------------------------------------------------------------------------- -bool SCSIPowerView::Write(const DWORD *cdb, const BYTE *buf, DWORD block) +bool SCSIPowerView::Write(const DWORD *cdb, const BYTE *buf, const DWORD length) { BYTE data_format = cdb[5]; // WORD data_length = (WORD)cdb[4] + ((WORD)cdb[3] << 8); @@ -691,250 +584,6 @@ bool SCSIPowerView::Write(const DWORD *cdb, const BYTE *buf, DWORD block) } } -// //--------------------------------------------------------------------------- -// // -// // RetrieveStats -// // -// // Command: 09 00 00 00 12 00 -// // Function: Retrieve MAC address and device statistics -// // Type: Input; returns 18 (decimal) bytes of data as follows: -// // - bytes 0-5: the current hardware ethernet (MAC) address -// // - bytes 6-17: three long word (4-byte) counters (little-endian). -// // Notes: The contents of the three longs are typically zero, and their -// // usage is unclear; they are suspected to be: -// // - long #1: frame alignment errors -// // - long #2: CRC errors -// // - long #3: frames lost -// // -// //--------------------------------------------------------------------------- -// int SCSIPowerView::RetrieveStats(const DWORD *cdb, BYTE *buffer) -// { -// int allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8); - -// // memset(buffer,0,18); -// // memcpy(&buffer[0],m_mac_addr,sizeof(m_mac_addr)); -// // uint32_t frame_alignment_errors; -// // uint32_t crc_errors; -// // uint32_t frames_lost; -// // // frame alignment errors -// // frame_alignment_errors = htonl(0); -// // memcpy(&(buffer[6]),&frame_alignment_errors,sizeof(frame_alignment_errors)); -// // // CRC errors -// // crc_errors = htonl(0); -// // memcpy(&(buffer[10]),&crc_errors,sizeof(crc_errors)); -// // // frames lost -// // frames_lost = htonl(0); -// // memcpy(&(buffer[14]),&frames_lost,sizeof(frames_lost)); - -// int response_size = sizeof(m_scsi_link_stats); -// memcpy(buffer, &m_scsi_link_stats, sizeof(m_scsi_link_stats)); - -// if (response_size > allocation_length) { -// response_size = allocation_length; -// } - -// // Success -// return response_size; -// } - -// //--------------------------------------------------------------------------- -// // -// // Enable or Disable the interface -// // -// // Command: 0e 00 00 00 00 XX (XX = 80 or 00) -// // Function: Enable (80) / disable (00) Ethernet interface -// // Type: No data transferred -// // Notes: After issuing an Enable, the initiator should avoid sending -// // any subsequent commands to the device for approximately 0.5 -// // seconds -// // -// //--------------------------------------------------------------------------- -// bool SCSIPowerView::EnableInterface(const DWORD *cdb) -// { -// bool result; -// if (cdb[5] & 0x80) { -// result = m_tap->Enable(); -// if (result) { -// LOGINFO("The DaynaPort interface has been ENABLED."); -// } -// else{ -// LOGWARN("Unable to enable the DaynaPort Interface"); -// } -// m_tap->Flush(); -// } -// else { -// result = m_tap->Disable(); -// if (result) { -// LOGINFO("The DaynaPort interface has been DISABLED."); -// } -// else{ -// LOGWARN("Unable to disable the DaynaPort Interface"); -// } -// } - -// return result; -// } - -// void SCSIPowerView::TestUnitReady(SASIDEV *controller) -// { -// // TEST UNIT READY Success - -// controller->Status(); -// } - -// void SCSIPowerView::Read6(SASIDEV *controller) -// { -// // Get record number and block number -// uint32_t record = ctrl->cmd[1] & 0x1f; -// record <<= 8; -// record |= ctrl->cmd[2]; -// record <<= 8; -// record |= ctrl->cmd[3]; -// ctrl->blocks=1; - -// // If any commands have a bogus control value, they were probably not -// // generated by the DaynaPort driver so ignore them -// if (ctrl->cmd[5] != 0xc0 && ctrl->cmd[5] != 0x80) { -// LOGTRACE("%s Control value %d, (%04X), returning invalid CDB", __PRETTY_FUNCTION__, ctrl->cmd[5], ctrl->cmd[5]); -// controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB); -// return; -// } - -// LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl->blocks); - -// ctrl->length = Read(ctrl->cmd, ctrl->buffer, record); -// LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl->length); - -// // Set next block -// ctrl->next = record + 1; - -// controller->DataIn(); -// } - -// void SCSIPowerView::Write6(SASIDEV *controller) -// { -// // Reallocate buffer (because it is not transfer for each block) -// if (ctrl->bufsize < DAYNAPORT_BUFFER_SIZE) { -// free(ctrl->buffer); -// ctrl->bufsize = DAYNAPORT_BUFFER_SIZE; -// ctrl->buffer = (BYTE *)malloc(ctrl->bufsize); -// } - -// DWORD data_format = ctrl->cmd[5]; - -// if(data_format == 0x00) { -// ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8); -// } -// else if (data_format == 0x80) { -// ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8) + 8; -// } -// else { -// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format); -// } -// LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->length, (int)ctrl->length, (unsigned int)data_format); - -// if (ctrl->length <= 0) { -// // Failure (Error) -// controller->Error(); -// return; -// } - -// // Set next block -// ctrl->blocks = 1; -// ctrl->next = 1; - -// controller->DataOut(); -// } - -// void SCSIPowerView::RetrieveStatistics(SASIDEV *controller) -// { -// ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer); -// if (ctrl->length <= 0) { -// // Failure (Error) -// controller->Error(); -// return; -// } - -// // Set next block -// ctrl->blocks = 1; -// ctrl->next = 1; - -// controller->DataIn(); -// } - -// //--------------------------------------------------------------------------- -// // -// // Set interface mode/Set MAC address -// // -// // Set Interface Mode (0c) -// // ----------------------- -// // Command: 0c 00 00 00 FF 80 (FF = 08 or 04) -// // Function: Allow interface to receive broadcast messages (FF = 04); the -// // function of (FF = 08) is currently unknown. -// // Type: No data transferred -// // Notes: This command is accepted by firmware 1.4a & 2.0f, but has no -// // effect on 2.0f, which is always capable of receiving broadcast -// // messages. In 1.4a, once broadcast mode is set, it remains set -// // until the interface is disabled. -// // -// // Set MAC Address (0c) -// // -------------------- -// // Command: 0c 00 00 00 FF 40 (FF = 08 or 04) -// // Function: Set MAC address -// // Type: Output; overrides built-in MAC address with user-specified -// // 6-byte value -// // Notes: This command is intended primarily for debugging/test purposes. -// // Disabling the interface resets the MAC address to the built-in -// // value. -// // -// //--------------------------------------------------------------------------- -// void SCSIPowerView::SetInterfaceMode(SASIDEV *controller) -// { -// // Check whether this command is telling us to "Set Interface Mode" or "Set MAC Address" - -// ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer); -// switch(ctrl->cmd[5]){ -// case SCSIPowerView::CMD_SCSILINK_SETMODE: -// // TODO Not implemented, do nothing -// controller->Status(); -// break; - -// case SCSIPowerView::CMD_SCSILINK_SETMAC: -// ctrl->length = 6; -// controller->DataOut(); -// break; - -// default: -// LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->cmd[5]); -// break; -// } -// } - -// void SCSIPowerView::SetMcastAddr(SASIDEV *controller) -// { -// ctrl->length = (DWORD)ctrl->cmd[4]; -// if (ctrl->length == 0) { -// LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl->cmd[2]); - -// // Failure (Error) -// controller->Error(); -// return; -// } - -// controller->DataOut(); -// } - -// void SCSIPowerView::EnableInterface(SASIDEV *controller) -// { -// bool status = EnableInterface(ctrl->cmd); -// if (!status) { -// // Failure (Error) -// controller->Error(); -// return; -// } - -// controller->Status(); -// } bool SCSIPowerView::ReceiveBuffer(int len, BYTE *buffer) { diff --git a/src/raspberrypi/devices/scsi_powerview.h b/src/raspberrypi/devices/scsi_powerview.h index 5d9db6c7..a988677b 100644 --- a/src/raspberrypi/devices/scsi_powerview.h +++ b/src/raspberrypi/devices/scsi_powerview.h @@ -49,6 +49,12 @@ private: void dump_command(SASIDEV *controller); + // Largest framebuffer supported by the Radius PowerView is 800x600 at 16-bit color (2 bytes per pixel) + const int POWERVIEW_BUFFER_SIZE = (800 * 600 * 2); + + DWORD m_powerview_resolution_x; + DWORD m_powerview_resolution_y; + public: SCSIPowerView(); ~SCSIPowerView(); @@ -59,7 +65,8 @@ public: // // Commands int Inquiry(const DWORD *cdb, BYTE *buffer) override; int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override; - bool Write(const DWORD *cdb, const BYTE *buf, DWORD block) override; + bool Write(const DWORD *cdb, const BYTE *buf, const DWORD length); + bool WriteFrameBuffer(const DWORD *cdb, const BYTE *buf, const DWORD length); // int WriteCheck(DWORD block) override; // WRITE check // int RetrieveStats(const DWORD *cdb, BYTE *buffer); @@ -70,7 +77,7 @@ public: void UnknownCommandC8(SASIDEV *controller); void UnknownCommandC9(SASIDEV *controller); - void UnknownCommandCA(SASIDEV *controller); + void CmdWriteFramebuffer(SASIDEV *controller); void UnknownCommandCB(SASIDEV *controller); void UnknownCommandCC(SASIDEV *controller); @@ -106,8 +113,8 @@ public: private: - int screen_width; - int screen_height; + uint32_t screen_width; + uint32_t screen_height; int fbfd; char *fb;