diff --git a/src/raspberrypi/devices/scsi_powerview.cpp b/src/raspberrypi/devices/scsi_powerview.cpp index 7e2710a2..a5b1e101 100644 --- a/src/raspberrypi/devices/scsi_powerview.cpp +++ b/src/raspberrypi/devices/scsi_powerview.cpp @@ -32,11 +32,6 @@ #include "log.h" #include "controllers/scsidev_ctrl.h" -static unsigned char reverse_table[256]; - -// #define DUMP_COLOR_PALETTE -// #define DUMP_FRAME_BUFFER - 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, @@ -53,9 +48,6 @@ SCSIPowerView::SCSIPowerView() : Disk("SCPV") AddCommand(SCSIDEV::eCmdPvWriteColorPalette, "Unknown PowerViewCB", &SCSIPowerView::CmdWriteColorPalette); AddCommand(SCSIDEV::eCmdUnknownPowerViewCC, "Unknown PowerViewCC", &SCSIPowerView::UnknownCommandCC); - // struct fb_var_screeninfo fbinfo; - // struct fb_fix_screeninfo fbfixinfo; - // create lookup table for (int i = 0; i < 256; i++) { unsigned char b = i; @@ -65,43 +57,6 @@ 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_px = 624; - this->screen_height_px = 840; - - this->fbfd = open("/dev/fb0", O_RDWR); - if (this->fbfd == -1) - err(1, "open /dev/fb0"); - - if (ioctl(this->fbfd, FBIOGET_VSCREENINFO, &fbinfo)) - err(1, "ioctl FBIOGET_VSCREENINFO"); - - if (ioctl(this->fbfd, FBIOGET_FSCREENINFO, &fbfixinfo)) - err(1, "ioctl FBIOGET_FSCREENINFO"); - - // if (fbinfo.bits_per_pixel != 32) - // errx(1, "TODO: support %d bpp", fbinfo.bits_per_pixel); - - this->fbwidth = fbinfo.xres; - this->fbheight = fbinfo.yres; - this->fbbpp = fbinfo.bits_per_pixel; - this->fblinelen = fbfixinfo.line_length; - this->fbsize = fbfixinfo.smem_len; - - LOGINFO("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, - this->fbfd, 0); - if ((int)this->fb == -1) - err(1, "mmap"); - - memset(this->fb, 0, this->fbsize); - framebuffer_black = 0; framebuffer_blue = (/*red*/ 0 << fbinfo.red.offset) | @@ -118,21 +73,16 @@ SCSIPowerView::SCSIPowerView() : Disk("SCPV") (/*alpha*/ 0 << fbinfo.transp.offset); - - this->m_powerview_resolution_x = 624; - this->m_powerview_resolution_y = 840; - - fbcon_cursor(false); - fbcon_blank(false); - ClearFrameBuffer(framebuffer_blue); - // Default to one bit color (black & white) if we don't know any better - color_depth = eColorsBW; + color_depth = eColorsNone; - LOGINFO("offsets - r:%d g:%d b:%d a:%d", fbinfo.red.offset, fbinfo.green.offset, fbinfo.blue.offset, fbinfo.transp.offset); } - +//--------------------------------------------------------------------------- +// +// Log a message to the framebuffer display +// +//--------------------------------------------------------------------------- void SCSIPowerView::fbcon_text(char* message) { int fd = open("/dev/tty1", O_RDWR); @@ -188,7 +138,7 @@ SCSIPowerView::~SCSIPowerView() // Re-enable the cursor fbcon_cursor(true); - munmap(this->fb, this->fbsize); + munmap(this->fb, fbfixinfo.smem_len); close(this->fbfd); for (auto const& command : commands) { @@ -211,39 +161,20 @@ void SCSIPowerView::ClearFrameBuffer(DWORD blank_color){ // For each column for (DWORD idx_col_x = 0; idx_col_x < 1024; idx_col_x++){ - - // int loc = (col * (this->fbbpp / 8)) + (row * this->fblinelen); uint32_t loc = ((idx_col_x) * (this->fbbpp / 8)) + ((idx_row_y) * 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_number, pixel, loc); *(this->fb + loc + 0) = (blank_color & 0xFF); *(this->fb + loc + 1) = (blank_color >> 8) & 0xFF; + // TODO: This should dynamically set the framebuffer memory, based upon the + // color depth. *(this->fb + loc + 2) = (blank_color >> 16) & 0xFF; - // for(int i=0 ; i< (this->fbbpp/8); i++){ - // *(this->fb + loc + i) = 0xFF; - // } } } } -void SCSIPowerView::dump_command(SASIDEV *controller){ - - LOGWARN(" %02X %02X %02X %02X %02X %02X %02X %02X [%02X] \n", - ctrl->cmd[0], - ctrl->cmd[1], - ctrl->cmd[2], - ctrl->cmd[3], - ctrl->cmd[4], - ctrl->cmd[5], - ctrl->cmd[6], - ctrl->cmd[7], - ctrl->cmd[8]); -} - //--------------------------------------------------------------------------- // // PowerView Read Configuration Parameter @@ -256,7 +187,6 @@ void SCSIPowerView::CmdReadConfig(SASIDEV *controller) // Set transfer amount ctrl->length = ctrl->cmd[6]; LOGWARN("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); - dump_command(controller); if (ctrl->length <= 0) { // Failure (Error) @@ -301,10 +231,9 @@ void SCSIPowerView::CmdReadConfig(SASIDEV *controller) //--------------------------------------------------------------------------- // -// Unknown Command C9 +// Unknown Command C9 - Write a configuration value? // //--------------------------------------------------------------------------- -// void SCSIPowerView::CmdPvWriteConfig(SASIDEV *controller) void SCSIPowerView::CmdWriteConfig(SASIDEV *controller) { @@ -312,7 +241,6 @@ void SCSIPowerView::CmdWriteConfig(SASIDEV *controller) ctrl->length = ctrl->cmd[6]; LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); - if (ctrl->length == 0){ controller->Status(); } @@ -330,7 +258,7 @@ void SCSIPowerView::CmdWriteConfig(SASIDEV *controller) //--------------------------------------------------------------------------- // -// Unknown Command CA +// Command to Write a Frame Buffer update // //--------------------------------------------------------------------------- void SCSIPowerView::CmdWriteFramebuffer(SASIDEV *controller) @@ -347,28 +275,8 @@ void SCSIPowerView::CmdWriteFramebuffer(SASIDEV *controller) uint16_t height_y = ctrl->cmd[7] + (ctrl->cmd[6] << 8); ctrl->length = width_x * height_y; - // if(ctrl->cmd[9] == 0){ - // ctrl->length = 0x9600; - // } - // else { - // ctrl->length = ctrl->cmd[7] * 2; - // } - LOGTRACE("%s Message Length %d [%08X]", __PRETTY_FUNCTION__, (int)ctrl->length, (unsigned int)ctrl->length); - // LOGDEBUG(" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X [%02X %02X]\n", - // ctrl->cmd[0], - // ctrl->cmd[1], - // ctrl->cmd[2], - // ctrl->cmd[3], - // ctrl->cmd[4], - // ctrl->cmd[5], - // ctrl->cmd[6], - // ctrl->cmd[7], - // ctrl->cmd[8], - // ctrl->cmd[9], - // ctrl->cmd[10], - // ctrl->cmd[11], - // ctrl->cmd[12]); + LOGTRACE("%s Message Length %d [%08X]", __PRETTY_FUNCTION__, (int)ctrl->length, (unsigned int)ctrl->length); if (ctrl->length <= 0) { // Failure (Error) @@ -386,7 +294,7 @@ void SCSIPowerView::CmdWriteFramebuffer(SASIDEV *controller) //--------------------------------------------------------------------------- // -// Unknown Command CB +// Receive a new color palette from the host // //--------------------------------------------------------------------------- void SCSIPowerView::CmdWriteColorPalette(SASIDEV *controller) @@ -423,12 +331,9 @@ void SCSIPowerView::CmdWriteColorPalette(SASIDEV *controller) //--------------------------------------------------------------------------- void SCSIPowerView::UnknownCommandCC(SASIDEV *controller) { - // Set transfer amount - // ctrl->length = ctrl->cmd[6]; ctrl->length = 0x8bb; LOGTRACE("%s Message Length %d", __PRETTY_FUNCTION__, (int)ctrl->length); - // dump_command(controller); if (ctrl->length <= 0) { // Failure (Error) controller->Error(); @@ -466,14 +371,58 @@ bool SCSIPowerView::Init(const map& params) { SetParams(params.empty() ? GetDefaultParams() : params); + 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; + } + + if (ioctl(this->fbfd, FBIOGET_VSCREENINFO, &fbinfo)){ + LOGERROR("Unable to retrieve framebuffer v screen info. Are you running as root?"); + return false; + } + + if (ioctl(this->fbfd, FBIOGET_FSCREENINFO, &fbfixinfo)){ + LOGERROR("Unable to retrieve framebuffer f screen info. Are you running as root?"); + return false; + } + + if (fbinfo.bits_per_pixel != 16){ + LOGERROR("PowerView emulation only supports 16 bits per pixel framebuffer. Currently set to %d", fbinfo.bits_per_pixel); + return false; + } + + 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; + } + + // Clear the framebuffer + memset(this->fb, 0, fbfixinfo.smem_len); + + // Hide the flashing cursor on the screen + fbcon_cursor(false); + + // Disable the automatic screen blanking (screen saver) + fbcon_blank(false); + + // 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; } -void SCSIPowerView::Open(const Filepath& path) -{ - -} - //--------------------------------------------------------------------------- // // INQUIRY @@ -511,20 +460,6 @@ int SCSIPowerView::Inquiry(const DWORD *cdb, BYTE *buf) } - - -//--------------------------------------------------------------------------- -// -// READ -// -//--------------------------------------------------------------------------- -int SCSIPowerView::Read(const DWORD *cdb, BYTE *buf, uint64_t block) -{ - int rx_packet_size = 0; - return rx_packet_size; - -} - bool SCSIPowerView::WriteConfiguration(const DWORD *cdb, const BYTE *buf, const DWORD length) { @@ -701,16 +636,16 @@ bool SCSIPowerView::WriteFrameBuffer(const DWORD *cdb, const BYTE *buf, const DW switch(color_depth){ case eColorDepth_t::eColorsBW: - sprintf(newstring, " Black & White %04X - %u x %u \r", color_depth, screen_width_px, screen_height_px); + 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 ); + 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); + 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); + sprintf(newstring, " UNKNOWN COLOR DEPTH!! %04X - %u x %u \r", color_depth, screen_width_px, screen_height_px); break; } fbcon_text(newstring); @@ -862,92 +797,3 @@ bool SCSIPowerView::WriteFrameBuffer(const DWORD *cdb, const BYTE *buf, const DW return true; } - -//https://www.i-programmer.info/programming/cc/12839-applying-c-framebuffer-graphics.html?start=1 -void SCSIPowerView::SetPixel(uint32_t x, uint32_t y, uint32_t r, - uint32_t g, uint32_t b) { - // char newstr[1024]; - uint32_t pixel = (r << fbinfo.red.offset)| - (g << fbinfo.green.offset)| - (b << fbinfo.blue.offset); -// this->fbbpp = fbinfo.bits_per_pixel; -// this->fblinelen = fbfixinfo.line_length; -// loc = ((idx_col_x + offset_col_px) * (this->fbbpp / 8)) + ((idx_row_y + offset_row_px) * fblinelen); - - uint32_t location = x*fbinfo.bits_per_pixel/8 + - y*fbfixinfo.line_length; - // sprintf(newstr, "%d:%d,", x, y); - // fbcon_text(newstr); - *(fb + location) = pixel & 0xFF; - *(fb + location) = (pixel >> 8) & 0xFF; - -} - -//--------------------------------------------------------------------------- -// -// Write -// -// Command: 0a 00 00 LL LL XX (LLLL is data length, XX = 80 or 00) -// Function: Write a packet at a time to the device (standard SCSI Write) -// Type: Output; the format of the data to be sent depends on the value -// of XX, as follows: -// - if XX = 00, LLLL is the packet length, and the data to be sent -// must be an image of the data packet -// - if XX = 80, LLLL is the packet length + 8, and the data to be -// sent is: -// PP PP 00 00 XX XX XX ... 00 00 00 00 -// where: -// PPPP is the actual (2-byte big-endian) packet length -// XX XX ... is the actual packet -// -//--------------------------------------------------------------------------- -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); - - if (data_format == 0x00){ - // m_tap->Tx(buf, data_length); - // LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length); - return true; - } - else if (data_format == 0x80){ - // // The data length is specified in the first 2 bytes of the payload - // data_length=(WORD)buf[1] + ((WORD)buf[0] << 8); - // m_tap->Tx(&buf[4], data_length); - // LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length); - return true; - } - else - { - // LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format); - LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format); - return true; - } -} - - -bool SCSIPowerView::ReceiveBuffer(int len, BYTE *buffer) -{ - int row = 0; - int col = 0; - - for (int i = 0; i < len; i++) { - unsigned char j = reverse_table[buffer[i]]; - - for (int bit = 0; bit < 8; bit++) { - int loc = (col * (this->fbbpp / 8)) + (row * this->fblinelen); - col++; - if (col % this->screen_width_px == 0) { - col = 0; - 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; - } - } - - return TRUE; -} diff --git a/src/raspberrypi/devices/scsi_powerview.h b/src/raspberrypi/devices/scsi_powerview.h index bb357eae..b0b0b1e9 100644 --- a/src/raspberrypi/devices/scsi_powerview.h +++ b/src/raspberrypi/devices/scsi_powerview.h @@ -47,37 +47,26 @@ private: enum eColorDepth_t : uint16_t {eColorsNone=0x0000, eColorsBW=0x0001, eColors16=0x0010, eColors256=0x0100}; - eColorDepth_t color_depth; void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSIPowerView::*)(SASIDEV *)); - void dump_command(SASIDEV *controller); - - // Largest framebuffer supported by the Radius PowerView is 800x600 at 16-bit color (2 bytes per pixel) + // Largest framebuffer supported by the Radius PowerView is 800x600 at 256 colors (1 bytes per pixel) + // Double it for now, because memory is cheap.... + // TODO: Remove the "*2" from this const int POWERVIEW_BUFFER_SIZE = (800 * 600 * 2); - DWORD m_powerview_resolution_x; - DWORD m_powerview_resolution_y; - - - void fbcon_cursor(bool blank); void fbcon_blank(bool blank); void fbcon_text(char* message); - void SetPixel(uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b); - public: SCSIPowerView(); ~SCSIPowerView(); bool Init(const map&) override; - void Open(const Filepath& path) override; // // 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, const DWORD length); 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); @@ -91,15 +80,14 @@ public: bool Dispatch(SCSIDEV *) override; - bool ReceiveBuffer(int len, BYTE *buffer); +private: void ClearFrameBuffer(DWORD blank_color); -private: - - uint32_t screen_width_px; - uint32_t screen_height_px; - + // Default to the lowest resolution supported by the PowerView (640x400) + uint32_t screen_width_px = 640; + uint32_t screen_height_px = 400; + eColorDepth_t color_depth = eColorsNone; struct fb_var_screeninfo fbinfo; struct fb_fix_screeninfo fbfixinfo; @@ -117,14 +105,14 @@ private: int fbfd; char *fb; - int fbwidth; - int fbheight; int fblinelen; - int fbsize; int fbbpp; + // Hard-coded inquiry response to match the real PowerView static const BYTE m_inquiry_response[]; + static unsigned char reverse_table[256]; + DWORD framebuffer_black; DWORD framebuffer_blue; DWORD framebuffer_yellow;