2021-12-27 23:32:41 +00:00
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
2022-01-10 02:47:54 +00:00
// Copyright (C) 2020-2021 akuker
// Copyright (C) 2020 joshua stein <jcs@jcs.org>
2021-12-27 23:32:41 +00:00
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
2022-01-10 02:47:54 +00:00
// [ Emulation of the Radius PowerView SCSI Display Adapter ]
2021-12-27 23:32:41 +00:00
//
2022-01-10 02:47:54 +00:00
// Note: This requires the Radius RadiusWare driver.
2021-12-27 23:32:41 +00:00
//
2022-01-10 02:47:54 +00:00
// Framebuffer integration originally done by Joshua Stein:
// https://github.com/jcs/RASCSI/commit/6da9e9f3ffcd38eb89413cd445f7407739c54bca
2021-12-27 23:32:41 +00:00
//
//---------------------------------------------------------------------------
# include "scsi_powerview.h"
# include <sstream>
2022-01-15 05:13:06 +00:00
# include <iomanip>
2021-12-27 23:32:41 +00:00
2022-01-10 02:47:54 +00:00
# include "exceptions.h"
2021-12-27 23:32:41 +00:00
# include <err.h>
# include <fcntl.h>
# include <linux/fb.h>
# include "os.h"
# include "disk.h"
# include <sys/mman.h>
2022-01-08 04:51:51 +00:00
# include "log.h"
2022-01-15 05:13:06 +00:00
# include "controllers/scsidev_ctrl.h"
2021-12-27 23:32:41 +00:00
2022-01-21 03:03:07 +00:00
unsigned char SCSIPowerView : : reverse_table [ 256 ] ;
2022-01-04 21:25:36 +00:00
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 ,
} ;
2021-12-27 23:32:41 +00:00
SCSIPowerView : : SCSIPowerView ( ) : Disk ( " SCPV " )
{
2022-01-22 20:58:02 +00:00
LOGTRACE ( " Entering %s " , __PRETTY_FUNCTION__ ) ;
2022-01-15 05:13:06 +00:00
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 ) ;
2022-01-08 22:04:34 +00:00
AddCommand ( SCSIDEV : : eCmdUnknownPowerViewCC , " Unknown PowerViewCC " , & SCSIPowerView : : UnknownCommandCC ) ;
2022-01-22 20:58:02 +00:00
LOGTRACE ( " %s - creating lookup table " , __PRETTY_FUNCTION__ ) ;
2021-12-27 23:32:41 +00:00
// 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 ;
}
2022-01-18 22:20:14 +00:00
framebuffer_black = 0 ;
framebuffer_blue = ( /*red*/ 0 < < fbinfo . red . offset ) |
( /*green*/ 0 < < fbinfo . green . offset ) |
( /*blue*/ 0xFF < < fbinfo . blue . offset ) |
2022-01-19 19:31:09 +00:00
( /*alpha*/ 0 < < fbinfo . transp . offset ) ;
2022-01-18 22:20:14 +00:00
framebuffer_yellow = ( /*red*/ 0 < < fbinfo . red . offset ) |
( /*green*/ 0xFF < < fbinfo . green . offset ) |
( /*blue*/ 0x0 < < fbinfo . blue . offset ) |
2022-01-19 19:31:09 +00:00
( /*alpha*/ 0 < < fbinfo . transp . offset ) ;
2022-01-18 22:20:14 +00:00
framebuffer_red = ( /*red*/ 0xFF < < fbinfo . red . offset ) |
( /*green*/ 0 < < fbinfo . green . offset ) |
( /*blue*/ 0 < < fbinfo . blue . offset ) |
2022-01-19 19:31:09 +00:00
( /*alpha*/ 0 < < fbinfo . transp . offset ) ;
2022-01-18 22:20:14 +00:00
2022-01-16 21:45:29 +00:00
// Default to one bit color (black & white) if we don't know any better
2022-01-21 03:03:07 +00:00
color_depth = eColorsBW ;
2022-01-22 20:58:02 +00:00
LOGTRACE ( " Done with %s " , __PRETTY_FUNCTION__ ) ;
2022-01-16 21:45:29 +00:00
}
2022-01-21 02:37:48 +00:00
//---------------------------------------------------------------------------
//
// Log a message to the framebuffer display
//
//---------------------------------------------------------------------------
2022-01-16 21:45:29 +00:00
void SCSIPowerView : : fbcon_text ( 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 ) ;
2021-12-27 23:32:41 +00:00
}
2022-01-16 20:13:01 +00:00
//---------------------------------------------------------------------------
//
// Enable/Disable the framebuffer flashing cursor
// From: https://linux-arm-kernel.infradead.narkive.com/XL0ylAHW/turn-off-framebuffer-cursor
//
//---------------------------------------------------------------------------
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 ) ;
}
//---------------------------------------------------------------------------
//
// Enable/disable the framebuffer blanking
// From: https://linux-arm-kernel.infradead.narkive.com/XL0ylAHW/turn-off-framebuffer-cursor
//
//---------------------------------------------------------------------------
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 ;
}
2021-12-27 23:32:41 +00:00
SCSIPowerView : : ~ SCSIPowerView ( )
{
2022-01-16 20:13:01 +00:00
// Re-enable the cursor
fbcon_cursor ( true ) ;
2021-12-27 23:32:41 +00:00
2022-01-21 02:37:48 +00:00
munmap ( this - > fb , fbfixinfo . smem_len ) ;
2021-12-27 23:32:41 +00:00
close ( this - > fbfd ) ;
for ( auto const & command : commands ) {
delete command . second ;
}
}
void SCSIPowerView : : AddCommand ( SCSIDEV : : scsi_command opcode , const char * name , void ( SCSIPowerView : : * execute ) ( SASIDEV * ) )
{
commands [ opcode ] = new command_t ( name , execute ) ;
}
2022-01-08 02:53:42 +00:00
2022-01-16 21:45:29 +00:00
void SCSIPowerView : : ClearFrameBuffer ( DWORD blank_color ) {
2022-01-15 05:13:06 +00:00
// For each row
2022-01-23 03:56:39 +00:00
for ( DWORD idx_row_y = 0 ; idx_row_y < fbinfo . yres - 1 ; idx_row_y + + ) {
2022-01-15 05:13:06 +00:00
// For each column
2022-01-23 03:56:39 +00:00
for ( DWORD idx_col_x = 0 ; idx_col_x < fbinfo . xres - 1 ; idx_col_x + + ) {
2022-01-15 05:13:06 +00:00
uint32_t loc = ( ( idx_col_x ) * ( this - > fbbpp / 8 ) ) + ( ( idx_row_y ) * fblinelen ) ;
2022-01-23 03:56:39 +00:00
uint8_t temp_color = blank_color ;
2022-01-15 05:13:06 +00:00
2022-01-23 03:56:39 +00:00
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 ;
}
2022-01-15 05:13:06 +00:00
}
}
}
2022-01-08 22:04:34 +00:00
//---------------------------------------------------------------------------
//
2022-01-15 05:13:06 +00:00
// PowerView Read Configuration Parameter
2022-01-08 22:04:34 +00:00
//
//---------------------------------------------------------------------------
2022-01-15 05:13:06 +00:00
// void SCSIPowerView::CmdPvReadConfig(SASIDEV *controller)
void SCSIPowerView : : CmdReadConfig ( SASIDEV * controller )
2022-01-08 22:04:34 +00:00
{
// Set transfer amount
ctrl - > length = ctrl - > cmd [ 6 ] ;
LOGWARN ( " %s Message Length %d " , __PRETTY_FUNCTION__ , ( int ) ctrl - > length ) ;
2022-01-08 02:53:42 +00:00
2022-01-08 22:04:34 +00:00
if ( ctrl - > length < = 0 ) {
// Failure (Error)
controller - > Error ( ) ;
return ;
}
2022-01-08 02:53:42 +00:00
2022-01-15 05:13:06 +00:00
// Response to "C8 00 00 31 83 00 01 00" is "00"
if ( ctrl - > cmd [ 4 ] = = 0x83 ) {
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 ;
}
2022-01-08 04:51:51 +00:00
2022-01-08 22:04:34 +00:00
// Set next block
ctrl - > blocks = 1 ;
ctrl - > next = 1 ;
2022-01-08 04:51:51 +00:00
2022-01-08 22:04:34 +00:00
controller - > DataIn ( ) ;
}
2022-01-08 02:53:42 +00:00
//---------------------------------------------------------------------------
//
2022-01-21 02:37:48 +00:00
// Unknown Command C9 - Write a configuration value?
2022-01-08 02:53:42 +00:00
//
//---------------------------------------------------------------------------
2022-01-15 05:13:06 +00:00
void SCSIPowerView : : CmdWriteConfig ( SASIDEV * controller )
2022-01-08 02:53:42 +00:00
{
// Set transfer amount
ctrl - > length = ctrl - > cmd [ 6 ] ;
2022-01-15 05:13:06 +00:00
LOGTRACE ( " %s Message Length %d " , __PRETTY_FUNCTION__ , ( int ) ctrl - > length ) ;
2022-01-19 23:25:29 +00:00
2022-01-08 04:51:51 +00:00
if ( ctrl - > length = = 0 ) {
controller - > Status ( ) ;
2022-01-08 02:53:42 +00:00
}
2022-01-08 04:51:51 +00:00
else
{
// Set next block
ctrl - > blocks = 1 ;
ctrl - > next = 1 ;
2022-01-08 02:53:42 +00:00
2022-01-08 04:51:51 +00:00
controller - > DataOut ( ) ;
}
2022-01-08 02:53:42 +00:00
}
//---------------------------------------------------------------------------
//
2022-01-21 02:37:48 +00:00
// Command to Write a Frame Buffer update
2022-01-08 02:53:42 +00:00
//
//---------------------------------------------------------------------------
2022-01-10 02:47:54 +00:00
void SCSIPowerView : : CmdWriteFramebuffer ( SASIDEV * controller )
2022-01-08 02:53:42 +00:00
{
2022-01-10 02:47:54 +00:00
// 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 ) ;
}
2022-01-08 02:53:42 +00:00
// Set transfer amount
2022-01-09 04:41:08 +00:00
uint16_t width_x = ctrl - > cmd [ 5 ] + ( ctrl - > cmd [ 4 ] < < 8 ) ;
uint16_t height_y = ctrl - > cmd [ 7 ] + ( ctrl - > cmd [ 6 ] < < 8 ) ;
ctrl - > length = width_x * height_y ;
2022-01-21 02:37:48 +00:00
LOGTRACE ( " %s Message Length %d [%08X] " , __PRETTY_FUNCTION__ , ( int ) ctrl - > length , ( unsigned int ) ctrl - > length ) ;
2022-01-09 04:41:08 +00:00
2022-01-08 02:53:42 +00:00
if ( ctrl - > length < = 0 ) {
// Failure (Error)
controller - > Error ( ) ;
return ;
}
// Set next block
ctrl - > blocks = 1 ;
ctrl - > next = 1 ;
controller - > DataOut ( ) ;
}
//---------------------------------------------------------------------------
//
2022-01-21 02:37:48 +00:00
// Receive a new color palette from the host
2022-01-08 02:53:42 +00:00
//
//---------------------------------------------------------------------------
2022-01-15 05:13:06 +00:00
void SCSIPowerView : : CmdWriteColorPalette ( SASIDEV * controller )
2022-01-08 02:53:42 +00:00
{
2022-01-19 19:31:09 +00:00
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 ;
2022-01-20 03:37:01 +00:00
LOGTRACE ( " %s Message Length %d " , __PRETTY_FUNCTION__ , ( int ) ctrl - > length ) ;
2022-01-19 19:31:09 +00:00
2022-01-19 21:03:26 +00:00
// The driver sends "1" for black and white, which is really
// TWO colors: Black and White
if ( received_color_depth = = eColorsBW ) {
ctrl - > length = 8 ;
}
2022-01-08 02:53:42 +00:00
if ( ctrl - > length < = 0 ) {
// Failure (Error)
controller - > Error ( ) ;
return ;
}
// Set next block
ctrl - > blocks = 1 ;
ctrl - > next = 1 ;
controller - > DataOut ( ) ;
}
//---------------------------------------------------------------------------
//
// Unknown Command CC
//
//---------------------------------------------------------------------------
void SCSIPowerView : : UnknownCommandCC ( SASIDEV * controller )
{
// Set transfer amount
2022-01-08 22:04:34 +00:00
ctrl - > length = 0x8bb ;
2022-01-15 05:13:06 +00:00
LOGTRACE ( " %s Message Length %d " , __PRETTY_FUNCTION__ , ( int ) ctrl - > length ) ;
2022-01-08 02:53:42 +00:00
if ( ctrl - > length < = 0 ) {
// Failure (Error)
controller - > Error ( ) ;
return ;
}
// Set next block
ctrl - > blocks = 1 ;
ctrl - > next = 1 ;
controller - > DataOut ( ) ;
}
2021-12-27 23:32:41 +00:00
bool SCSIPowerView : : Dispatch ( SCSIDEV * controller )
{
ctrl = controller - > GetCtrl ( ) ;
if ( commands . count ( static_cast < SCSIDEV : : scsi_command > ( ctrl - > cmd [ 0 ] ) ) ) {
command_t * command = commands [ static_cast < SCSIDEV : : scsi_command > ( 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 : : Init ( const map < string , string > & params )
{
2022-01-22 20:58:02 +00:00
LOGTRACE ( " Entering %s " , __PRETTY_FUNCTION__ ) ;
2021-12-27 23:32:41 +00:00
SetParams ( params . empty ( ) ? GetDefaultParams ( ) : params ) ;
2022-01-21 02:37:48 +00:00
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 ;
}
2022-01-22 20:58:02 +00:00
LOGTRACE ( " %s - /dev/fb0 opened " , __PRETTY_FUNCTION__ ) ;
2021-12-27 23:32:41 +00:00
2022-01-21 02:37:48 +00:00
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 ;
}
2022-01-10 02:47:54 +00:00
2022-01-21 02:37:48 +00:00
if ( fbinfo . bits_per_pixel ! = 16 ) {
LOGERROR ( " PowerView emulation only supports 16 bits per pixel framebuffer. Currently set to %d " , fbinfo . bits_per_pixel ) ;
2022-01-22 20:58:02 +00:00
LOGERROR ( " Try running \" fbset -depth 16 \" " ) ;
2022-01-21 02:37:48 +00:00
return false ;
}
2022-01-22 20:58:02 +00:00
LOGTRACE ( " %s Done capturing FB info " , __PRETTY_FUNCTION__ ) ;
2022-01-21 02:37:48 +00:00
fbbpp = fbinfo . bits_per_pixel ;
fblinelen = fbfixinfo . line_length ;
fb = ( char * ) mmap ( 0 , fbfixinfo . smem_len , PROT_READ | PROT_WRITE , MAP_SHARED , fbfd , 0 ) ;
2023-03-09 03:35:08 +00:00
if ( fb = = ( char * ) - 1 ) {
2022-01-21 02:37:48 +00:00
LOGERROR ( " Unable to mmap the framebuffer memory. Are you running as root? " ) ;
return false ;
}
2022-01-22 20:58:02 +00:00
LOGTRACE ( " %s mmap complete " , __PRETTY_FUNCTION__ ) ;
2022-01-21 02:37:48 +00:00
// Clear the framebuffer
memset ( this - > fb , 0 , fbfixinfo . smem_len ) ;
2022-01-22 20:58:02 +00:00
LOGTRACE ( " %s done clearing framebuffer " , __PRETTY_FUNCTION__ ) ;
2022-01-21 02:37:48 +00:00
// Hide the flashing cursor on the screen
fbcon_cursor ( false ) ;
// Disable the automatic screen blanking (screen saver)
fbcon_blank ( false ) ;
2022-01-22 20:58:02 +00:00
LOGTRACE ( " %s Done disable blanking " , __PRETTY_FUNCTION__ ) ;
2022-01-21 02:37:48 +00:00
// 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 ;
2021-12-27 23:32:41 +00:00
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIPowerView : : Inquiry ( const DWORD * cdb , BYTE * buf )
{
int allocation_length = cdb [ 4 ] + ( ( ( DWORD ) cdb [ 3 ] ) < < 8 ) ;
2022-01-04 21:25:36 +00:00
if ( allocation_length > 0 ) {
if ( ( unsigned int ) allocation_length > sizeof ( m_inquiry_response ) ) {
allocation_length = ( int ) sizeof ( m_inquiry_response ) ;
2021-12-27 23:32:41 +00:00
}
2022-01-04 21:25:36 +00:00
memcpy ( buf , m_inquiry_response , allocation_length ) ;
// // 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;
// // Padded vendor, product, revision
// memcpy(&buf[8], GetPaddedName().c_str(), 28);
2021-12-27 23:32:41 +00:00
}
LOGTRACE ( " response size is %d " , allocation_length ) ;
return allocation_length ;
}
2022-01-04 21:25:36 +00:00
2022-01-15 05:13:06 +00:00
bool SCSIPowerView : : WriteConfiguration ( const DWORD * cdb , const BYTE * buf , const DWORD length )
{
std : : stringstream ss ;
ss < < std : : hex ;
for ( DWORD 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 ;
}
bool SCSIPowerView : : WriteUnknownCC ( const DWORD * cdb , const BYTE * buf , const DWORD length )
{
if ( length > sizeof ( unknown_cc_data ) ) {
2023-03-09 03:35:08 +00:00
LOGERROR ( " %s Received Unknown CC data that is larger (%d bytes) than allocated size (%d bytes) " , __PRETTY_FUNCTION__ , length , ( int ) sizeof ( unknown_cc_data ) ) ;
2022-01-15 05:13:06 +00:00
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 ;
}
bool SCSIPowerView : : WriteColorPalette ( const DWORD * cdb , const BYTE * buf , const DWORD length )
{
2022-01-16 21:45:29 +00:00
if ( length < = 1 ) {
LOGDEBUG ( " %s Received Color Palette with depth of %u " , __PRETTY_FUNCTION__ , length ) ;
// This is still a valid condition.
return true ;
}
2022-01-15 05:13:06 +00:00
if ( length > sizeof ( color_palette ) ) {
2023-03-09 03:35:08 +00:00
LOGERROR ( " %s Received Color Palette that is larger (%d bytes) than allocated size (%d bytes) " , __PRETTY_FUNCTION__ , length , ( int ) sizeof ( color_palette ) ) ;
2022-01-15 05:13:06 +00:00
return false ;
}
2022-01-19 19:31:09 +00:00
eColorDepth_t new_color = ( eColorDepth_t ) ( ( uint16_t ) cdb [ 4 ] + ( ( uint16_t ) cdb [ 3 ] < < 8 ) ) ;
2022-01-16 21:45:29 +00:00
2022-01-19 19:31:09 +00:00
if ( new_color = = eColorDepth_t : : eColorsNone ) {
// This is currently unknown functionality. So, just ignore it.
return true ;
}
2022-01-16 21:45:29 +00:00
ClearFrameBuffer ( framebuffer_red ) ;
2022-01-19 19:31:09 +00:00
color_depth = new_color ;
2022-01-20 03:37:01 +00:00
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 ;
}
// 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 ) ;
2022-01-19 19:31:09 +00:00
2022-01-19 21:03:26 +00:00
# ifdef DUMP_COLOR_PALETTE
FILE * fp ;
char newstring [ 1024 ] ;
2022-01-19 22:56:37 +00:00
static int dump_idx = 0 ;
2022-01-19 21:03:26 +00:00
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 " ) ;
2022-01-18 22:20:14 +00:00
2022-01-19 21:03:26 +00:00
sprintf ( newstring , " length: %u \n " , length ) ;
2022-01-18 22:20:14 +00:00
2022-01-19 21:03:26 +00:00
fputs ( newstring , fp ) ;
2022-01-18 22:20:14 +00:00
2022-01-19 21:03:26 +00:00
for ( DWORD i = 0 ; i < length ; i + = 4 ) {
if ( i % 16 = = 0 ) {
sprintf ( newstring , " %u: " , i ) ;
fputs ( newstring , fp ) ;
}
2022-01-18 22:20:14 +00:00
2022-01-19 21:03:26 +00:00
sprintf ( newstring , " [%02X %02X%02X%02X] " , buf [ i + 0 ] , buf [ i + 1 ] , buf [ i + 2 ] , buf [ i + 3 ] ) ;
fputs ( newstring , fp ) ;
2022-01-18 22:20:14 +00:00
2022-01-19 21:03:26 +00:00
if ( i % 16 = = 12 ) {
2022-01-18 22:20:14 +00:00
2022-01-19 21:03:26 +00:00
fputs ( " \n " , fp ) ;
}
}
fclose ( fp ) ;
# endif
2022-01-18 22:20:14 +00:00
2022-01-15 05:13:06 +00:00
return true ;
}
2022-01-10 02:47:54 +00:00
bool SCSIPowerView : : WriteFrameBuffer ( const DWORD * cdb , const BYTE * buf , const DWORD length )
{
2022-01-19 22:56:37 +00:00
char newstring [ 1024 ] ;
2022-01-16 21:45:29 +00:00
// 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 ;
2022-01-10 02:47:54 +00:00
2022-01-16 21:45:29 +00:00
// 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 ) ;
bool full_framebuffer_refresh = ( offset = = 0 ) & & ( cdb [ 9 ] = = 0x00 ) ;
switch ( color_depth ) {
2022-01-19 19:31:09 +00:00
case ( eColorsBW ) :
2022-01-16 21:45:29 +00:00
// 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 ;
2022-01-19 19:31:09 +00:00
case ( eColors16 ) :
2022-01-16 21:45:29 +00:00
// 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 ;
2022-01-19 19:31:09 +00:00
case ( eColors256 ) :
2022-01-16 21:45:29 +00:00
// Two Bytes per pixel
update_width_px = update_width_x_bytes ;
2022-01-19 19:59:04 +00:00
offset_row_px = ( uint32_t ) ( offset / screen_width_px ) ;
offset_col_px = ( uint32_t ) ( offset % screen_width_px ) ;
2022-01-16 21:45:29 +00:00
break ;
default :
update_width_px = 0 ;
offset_row_px = 0 ;
offset_col_px = 0 ;
2022-01-19 19:31:09 +00:00
LOGINFO ( " No color depth available! %04X " , color_depth ) ;
2022-01-16 21:45:29 +00:00
break ;
}
update_height_px = update_height_y_bytes ;
if ( full_framebuffer_refresh ) {
screen_width_px = update_width_px ;
screen_height_px = update_height_px ;
2021-12-27 23:32:41 +00:00
2022-01-16 22:35:11 +00:00
switch ( color_depth ) {
2022-01-19 19:31:09 +00:00
case eColorDepth_t : : eColorsBW :
2022-01-21 02:37:48 +00:00
sprintf ( newstring , " Black & White %04X - %u x %u \r " , color_depth , screen_width_px , screen_height_px ) ;
2022-01-16 22:35:11 +00:00
break ;
2022-01-19 19:31:09 +00:00
case eColorDepth_t : : eColors16 :
2022-01-21 02:37:48 +00:00
sprintf ( newstring , " 16 colors/grays %04X - %u x %u \r " , color_depth , screen_width_px , screen_height_px ) ;
2022-01-16 22:35:11 +00:00
break ;
2022-01-19 19:31:09 +00:00
case eColorDepth_t : : eColors256 :
2022-01-21 02:37:48 +00:00
sprintf ( newstring , " 256 colors/grays %04X - %u x %u \r " , color_depth , screen_width_px , screen_height_px ) ;
2022-01-16 22:35:11 +00:00
break ;
default :
2022-01-21 02:37:48 +00:00
sprintf ( newstring , " UNKNOWN COLOR DEPTH!! %04X - %u x %u \r " , color_depth , screen_width_px , screen_height_px ) ;
2022-01-16 22:35:11 +00:00
break ;
}
fbcon_text ( newstring ) ;
2021-12-27 23:32:41 +00:00
2022-01-16 22:35:11 +00:00
}
2022-01-10 02:47:54 +00:00
2022-01-18 23:30:05 +00:00
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 ) ;
2022-01-19 19:31:09 +00:00
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 ) {
2022-01-21 03:10:25 +00:00
// 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 ) ;
}
}
2022-01-19 19:31:09 +00:00
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 ;
}
2022-01-10 02:47:54 +00:00
2022-01-19 19:59:04 +00:00
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 ) ;
2022-01-21 03:10:25 +00:00
DWORD random_print = rand ( ) % ( update_height_px * update_width_px ) ;
// For each row
for ( DWORD idx_row_y = 0 ; idx_row_y < ( update_height_px ) ; idx_row_y + + ) {
// 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 ;
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 ;
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 ;
}
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 ;
}
2022-01-19 19:59:04 +00:00
2022-01-21 03:10:25 +00:00
loc = ( ( idx_col_x + offset_col_px ) * ( this - > fbbpp / 8 ) ) + ( ( idx_row_y + offset_row_px ) * fblinelen ) ;
2022-01-19 19:59:04 +00:00
2022-01-21 03:10:25 +00:00
uint32_t data_idx , red , green , blue ;
2022-01-19 19:59:04 +00:00
2022-01-21 03:10:25 +00:00
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 ] ;
2022-01-10 02:47:54 +00:00
2022-01-21 03:10:25 +00:00
blue > > = ( 8 - fbinfo . red . length ) ;
green > > = ( 8 - fbinfo . green . length ) ;
red > > = ( 8 - fbinfo . blue . length ) ;
2022-01-10 02:47:54 +00:00
2022-01-21 03:10:25 +00:00
uint32_t fb_pixel = ( red < < fbinfo . red . offset ) |
( green < < fbinfo . green . offset ) |
( blue < < fbinfo . blue . offset ) ;
2022-01-19 22:56:37 +00:00
2022-01-19 23:25:29 +00:00
if ( random_print = = ( idx_col_x * idx_row_y ) ) {
2022-01-20 03:37:01 +00:00
LOGDEBUG ( " idx:%d (%02X) [%02X %02X %02X %02X] fb_pixel:%08X " , pixel_color_idx , pixel_color_idx , data_idx , red , green , blue , fb_pixel ) ;
2022-01-19 23:25:29 +00:00
}
2022-01-19 22:56:37 +00:00
2022-01-20 03:37:01 +00:00
* ( this - > fb + loc + 1 ) = ( BYTE ) ( ( fb_pixel > > 8 ) & 0xFF ) ;
* ( this - > fb + loc + 0 ) = ( BYTE ) ( ( fb_pixel ) & 0xFF ) ;
2022-01-10 02:47:54 +00:00
}
}
2022-01-19 21:03:26 +00:00
# ifdef DUMP_FRAME_BUFFER
//******************************************************************************
FILE * fp ;
2022-01-19 22:56:37 +00:00
static int dumpfb_idx = 0 ;
2022-01-19 21:03:26 +00:00
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 ) ;
fputs ( newstring , fp ) ;
for ( DWORD 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 ) ;
if ( i % 16 = = 12 ) {
fputs ( " \n " , fp ) ;
}
}
fclose ( fp ) ;
# endif
//******************************************************************************
2022-01-10 02:47:54 +00:00
return true ;
2021-12-27 23:32:41 +00:00
}