merge in latest trunk

This commit is contained in:
akuker
2020-09-11 09:52:39 -05:00
323 changed files with 845083 additions and 11071 deletions

8
src/php/.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
root = true
[*.{html,php,htm}]
indent_style = space
indent_size = 3
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

31
src/php/LICENSE Normal file
View File

@@ -0,0 +1,31 @@
BSD 3-Clause License
Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
Copyright (C) 2014-2020 GIMONS
Copyright (c) 2020, akuker
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

260
src/php/lib_rascsi.php Normal file
View File

@@ -0,0 +1,260 @@
<!-- PHP source code for controlling the RaSCSI - 68kmla edition with a web interface. -->
<!-- Copyright (c) 2020 akuker -->
<!-- Distributed under the BSD-3 Clause License -->
<!-- Note: the origina rascsi-php project was under MIT license.-->
<?php
$DEBUG_ENABLE=0;
$FILE_PATH='/home/pi/images';
// Limit the maximum upload file size to 1GB
$MAX_UPLOAD_FILE_SIZE=1000000000;
$ALLOWED_FILE_TYPES=array('iso','hda');
function html_generate_header(){
echo ' <table width="100%" >'. PHP_EOL;
echo ' <tr style="background-color: black;">'. PHP_EOL;
echo ' <td style="background-color: black;"><a href=http://github.com/akuker/RASCSI><h1>RaSCSI - 68kmla Edition</h1></a></td>'. PHP_EOL;
echo ' <td style="background-color: black;">'. PHP_EOL;
echo ' <form action="rascsi.php">'. PHP_EOL;
echo ' <input type="submit" value="Go Home"/>'. PHP_EOL;
if($GLOBALS['DEBUG_ENABLE']){
echo ' <p style="color:#595959">Debug Timestamp: '.time().'</p>'. PHP_EOL;
}
echo ' </form>'. PHP_EOL;
echo ' </td>'. PHP_EOL;
echo ' </tr>'. PHP_EOL;
echo ' </table>'. PHP_EOL;
//echo(exec('whoami'));
}
function html_generate_image_file_select_list(){
$all_files = get_all_files();
foreach(explode(PHP_EOL, $all_files) as $this_file){
if(strpos($this_file, 'total') === 0){
continue;
}
$file_name = file_name_from_ls($this_file);
if(strlen($file_name) === 0){
continue;
}
// Ignore files that start with a .
if(strpos($file_name, '.') === 0){
continue;
}
echo '<option value="'.$file_name.'">'.$file_name.'</option>'.PHP_EOL;
}
}
function html_generate_scsi_id_select_list(){
echo '<select>'. PHP_EOL;
foreach(range(0,7) as $id){
echo '<option value="'.$id.'">'.$id.'</option>'. PHP_EOL;
}
echo '</select>'. PHP_EOL;
}
function html_generate_scsi_type_select_list(){
echo '<select name=type>'. PHP_EOL;
$options = array("Hard Disk", "CD-ROM", "Zip Drive", "Ethernet Tap", "Filesystem Bridge");
foreach($options as $type){
echo '<option value="'.$type.'">'.$type.'</option>'. PHP_EOL;
}
echo '</select>'. PHP_EOL;
}
function html_generate_warning($message){
echo ' <table width="100%" >'. PHP_EOL;
echo ' <tr style="background-color: red;">'. PHP_EOL;
echo ' <td style="background-color: red;">'. PHP_EOL;
echo ' <font size=+2>'.$message.'</font>'. PHP_EOL;
echo ' </td>'. PHP_EOL;
echo ' </tr>'. PHP_EOL;
echo ' </table>'. PHP_EOL;
}
function html_generate_success_message($message){
echo ' <table width="100%" >'. PHP_EOL;
echo ' <tr style="background-color: green;">'. PHP_EOL;
echo ' <td style="background-color: green;">'. PHP_EOL;
echo ' <font size=+2>Success</font>'. PHP_EOL;
echo ' </td>'. PHP_EOL;
echo ' </tr>'. PHP_EOL;
if(strlen($message) > 0){
echo ' <tr style="background-color: green;">'. PHP_EOL;
echo ' <td style="background-color: green;">'. PHP_EOL;
echo ' '.$message.PHP_EOL;
echo ' </td>'. PHP_EOL;
echo ' </tr>'. PHP_EOL;
}
echo ' </table>'. PHP_EOL;
}
function html_generate_ok_to_go_home(){
echo ' <form action="rascsi.php">'. PHP_EOL;
echo ' <input type="submit" value="OK"/>'. PHP_EOL;
echo ' </form>'. PHP_EOL;
}
function current_rascsi_config() {
$raw_output = shell_exec("/usr/local/bin/rasctl -l");
$rasctl_lines = explode(PHP_EOL, $raw_output);
echo ' <br>'. PHP_EOL;
echo ' <h2>Current RaSCSI Configuration</h2>'. PHP_EOL;
echo ' <table border="black">'. PHP_EOL;
echo ' <tr>'. PHP_EOL;
echo ' <td><b>SCSI ID</b></td>'. PHP_EOL;
echo ' <td><b>Type</b></td>'. PHP_EOL;
echo ' <td><b>File</b></td>'. PHP_EOL;
echo ' <td><b>File Ops</b></td>'. PHP_EOL;
echo ' <td><b>Device Ops</b></td>'. PHP_EOL;
echo ' </tr>'. PHP_EOL;
$scsi_ids = array();
foreach ($rasctl_lines as $current_line)
{
if(strlen($current_line) === 0){
continue;
}
if(strpos($current_line, '+----') === 0){
continue;
}
if(strpos($current_line, '| ID | UN') === 0){
continue;
}
$segments = explode("|", $current_line);
$id_config = array();
$id_config['id'] = trim($segments[1]);
$id_config['type'] = trim($segments[3]);
$id_config['file'] = trim($segments[4]);
$scsi_ids[$id_config['id']] = $id_config;
}
foreach (range(0,7) as $id){
echo ' <tr>'. PHP_EOL;
echo ' <td style="text-align:center">'.$id.'</td>'. PHP_EOL;
if(isset($scsi_ids[$id]))
{
echo ' <td style="text-align:center">'.$scsi_ids[$id]['type'].'</td>'. PHP_EOL;
if(strtolower($scsi_ids[$id]['file']) == "no media"){
echo ' <td>'.PHP_EOL;
echo ' <form action="rascsi_action.php" method="post">'. PHP_EOL;
echo ' <select name="file_name">'.PHP_EOL;
echo ' <option value="None">None</option>'.PHP_EOL;
html_generate_image_file_select_list();
echo ' </select>'.PHP_EOL;
echo ' <input type="hidden" name="command" value="insert_disk" />'. PHP_EOL;
echo ' <input type="hidden" name="id" value="'.$id.'" />'. PHP_EOL;
echo ' <input type="hidden" name="file" value="'.$scsi_ids[$id]['file'].'" />'. PHP_EOL;
echo ' </td><td>'.PHP_EOL;
echo ' <input type="submit" name="insert_disk" value="Insert" />'. PHP_EOL;
echo ' </form>'. PHP_EOL;
echo ' </td>'.PHP_EOL;
}
else{
// rascsi inserts "WRITEPROTECT" for the read-only drives. We want to display that differently.
echo ' <form action="rascsi_action.php" method="post">'. PHP_EOL;
echo ' <td>'.str_replace('(WRITEPROTECT)', '', $scsi_ids[$id]['file']). PHP_EOL;
echo ' </td><td>'.PHP_EOL;
if(strtolower($scsi_ids[$id]['type']) == 'sccd'){
echo ' <input type="hidden" name="command" value="eject_disk" />'. PHP_EOL;
echo ' <input type="hidden" name="id" value="'.$id.'" />'. PHP_EOL;
echo ' <input type="hidden" name="file" value="'.$scsi_ids[$id]['file'].'" />'. PHP_EOL;
echo ' <input type="submit" name="eject_disk" value="Eject" />'. PHP_EOL;
}
echo ' </td>'.PHP_EOL;
echo ' </form>'. PHP_EOL;
}
echo ' <td>'. PHP_EOL;
echo ' <form action="rascsi_action.php" method="post">'. PHP_EOL;
echo ' <input type="hidden" name="command" value="remove_device" />'. PHP_EOL;
echo ' <input type="hidden" name="id" value="'.$id.'" />'. PHP_EOL;
echo ' <input type="submit" name="remove_device" value="Disconnect" />'. PHP_EOL;
echo ' </form>'. PHP_EOL;
echo ' </td>'. PHP_EOL;
}
else
{
echo ' <td style="text-align:center">-</td>'. PHP_EOL;
echo ' <td>-</td>'. PHP_EOL;
echo ' <td></td>'. PHP_EOL;
echo ' <td>'. PHP_EOL;
echo ' <form action="rascsi_action.php" method="post">'. PHP_EOL;
echo ' <input type="hidden" name="command" value="connect_new_device" />'. PHP_EOL;
echo ' <input type="hidden" name="id" value="'.$id.'" />'. PHP_EOL;
echo ' <input type="submit" name="connect_new_device" value="Connect New" />'. PHP_EOL;
echo ' </form>'. PHP_EOL;
echo ' </td>'. PHP_EOL;
}
echo ' </form>'. PHP_EOL;
echo ' </tr>'. PHP_EOL;
}
echo '</table>'. PHP_EOL;
}
function get_all_files()
{
$raw_ls_output = shell_exec('ls --time-style="+\"%Y-%m-%d %H:%M:%S\"" -alh --quoting-style=c '.$GLOBALS['FILE_PATH']);
return $raw_ls_output;
}
function mod_date_from_ls($value){
$ls_pieces = explode("\"", $value);
if(count($ls_pieces)<1){
return "";
}
return $ls_pieces[1];
}
function file_name_from_ls($value){
$ls_pieces = explode("\"", $value);
if(count($ls_pieces) < 4){
return "";
}
return $ls_pieces[3];
}
function file_size_from_ls($value){
$ls_pieces = explode("\"", $value);
$file_props = preg_split("/\s+/", $ls_pieces[0]);
return $file_props[4];
}
function file_category_from_file_name($value){
if(strpos($value,".iso") > 0){
return "CD-ROM Image";
}
if(strpos($value,".hda") > 0){
return "Hard Disk Image";
}
return "Unknown type: " . $value;
}
function type_string_to_rasctl_type($typestr){
if(strcasecmp($typestr,"Hard Disk") == 0){
return "hd";
}
if(strcasecmp($typestr,"CD-ROM") == 0){
return "cd";
}
if(strcasecmp($typestr,"Zip Drive") == 0){
}
if(strcasecmp($typestr,"Filesystem bridge") == 0){
return "bridge";
}
return "";
}
?>

9
src/php/rascsi.html Normal file
View File

@@ -0,0 +1,9 @@
<HTML>
<HEAD> <TITLE>RaSCSI Control Page</TITLE></HEAD>
<FRAMESET ROWS="20px,*" BORDER=0>
<FRAME SRC="status.php" NAME="rascsi_status">
<FRAME SRC="rascsi.php" NAME="rascsi_control">
<NOFRAMES>You must use a browser that can display frames
to see this page. </NOFRAMES>
</FRAMESET>
</HTML>

135
src/php/rascsi.php Normal file
View File

@@ -0,0 +1,135 @@
<!-- PHP source code for controlling the RaSCSI - 68kmla edition with a web interface. -->
<!-- Copyright (c) 2020 akuker -->
<!-- Distributed under the BSD-3 Clause License -->
<!-- Note: the origina rascsi-php project was under MIT license.-->
<!DOCTYPE html>
<html>
<head>
<title>RaSCSI Main Control Page</title>
<link rel="stylesheet" href="rascsi_styles.css">
</head>
<body>
<?php
include 'lib_rascsi.php';
html_generate_header();
current_rascsi_config();
?>
<br>
<h2>Image File Management</h2>
<table border="black">
<tr>
<td><b>Location</b></td>
<td><b>Filename</b></td>
<td><b>Size</b></td>
<td><b>Type</b></td>
<td><b>Date Modified</b></td>
<td><b>Actions</b></td>
</tr>
<tr>
<?php
// Generate the table with all of the file names in it.....
$all_files = get_all_files();
foreach(explode(PHP_EOL, $all_files) as $this_file){
if(strpos($this_file, 'total') === 0){
continue;
}
$file_name = file_name_from_ls($this_file);
if(strlen($file_name) === 0){
continue;
}
// Ignore file names that start with .
if(strpos($file_name,".") === 0){
continue;
}
echo '<tr>'.PHP_EOL;
echo ' <td>SD Card</td>'.PHP_EOL;
echo ' <td>'.$file_name.'</td>'.PHP_EOL;
echo ' <td>'.file_size_from_ls($this_file).'</td>'.PHP_EOL;
echo ' <td>'.file_category_from_file_name($file_name).'</td>'.PHP_EOL;
echo ' <td>'.mod_date_from_ls($this_file).'</td>'.PHP_EOL;
echo ' <td>'.PHP_EOL;
echo ' <form action="rascsi_action.php" method="post">'.PHP_EOL;
echo ' <input type="hidden" name="command" value="delete_file"/>'.PHP_EOL;
echo ' <input type="hidden" name="file_name" value="'.$file_name.'"/>'.PHP_EOL;
echo ' <input type="submit" value="Delete">'.PHP_EOL;
echo ' </form>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo '</tr>'.PHP_EOL;
}
?>
</table>
<br>
<br>
<h2>Upload New Image File</h2>
<form action="rascsi_upload.php" method="post" enctype="multipart/form-data">
<table style="border: none">
<tr style="border: none">
<td style="border: none; vertical-align:top;">
<input type="file" id="filename" name="file_name"><br><br>
</td>
<td style="border: none; vertical-align:top;">
<input type="submit" value="Upload" name="submit">
</td>
</tr>
</table>
</form>
<br>
<h2>Create New Empty HD Image</h2>
<form action="rascsi_action.php" method="post">
<input type="hidden" name="command" value="create_new_image" />
<input type="submit" value="Create New">
</form>
<br>
<h2>RaSCSI Service Status</h2>
<table style="border: none">
<tr style="border: none">
<td style="border: none; vertical-align:top;">
<form action="rascsi_action.php" method="post">
<input type="hidden" name="command" value="restart_rascsi_service" />
<input type="submit" name="restart_rascsi_service" value="Restart RaSCSI service" />
</form>
</td>
<td style="border: none; vertical-align:top;">
<form action="rascsi_action.php" method="post">
<input type="hidden" name="command" value="stop_rascsi_service" />
<input type="submit" name="stop_rascsi_service" value="Stop RaSCSI service" />
</form>
</td>
</tr>
</table>
<br>
<h2>Raspberry Pi Operations</h2>
<table style="border: none">
<tr style="border: none">
<td style="border: none; vertical-align:top;">
<form action="rascsi_action.php" method="post">
<input type="hidden" name="command" value="reboot_raspberry_pi" />
<input type="submit" name="reboot_rasbperry_pi" value="Reboot Raspberry Pi" />
</form>
</td>
<td style="border: none; vertical-align:top;">
<form action="rascsi_action.php" method="post">
<input type="hidden" name="command" value="shutdown_raspberry_pi" />
<input type="submit" name="shutdown_raspberry_pi" value="Shut Down Raspberry Pi" />
</form>
</td>
</tr>
</table>
</body>
</html>

297
src/php/rascsi_action.php Normal file
View File

@@ -0,0 +1,297 @@
<!-- PHP source code for controlling the RaSCSI - 68kmla edition with a web interface. -->
<!-- Copyright (c) 2020 akuker -->
<!-- Distributed under the BSD-3 Clause License -->
<!DOCTYPE html>
<html>
<head>
<title>RaSCSI Action Page</title>
<link rel="stylesheet" href="rascsi_styles.css">
</head>
<body>
<?php
include 'lib_rascsi.php';
html_generate_header();
echo '<br>';
if($GLOBALS['DEBUG_ENABLE']){
echo '<table>'.PHP_EOL;
echo ' <tr><td><p style="color:gray">Debug stuff</p></td></tr>'.PHP_EOL;
echo ' <tr><td>';
echo '<p style="color:gray">Post values......................'.PHP_EOL;
echo '<br> '.PHP_EOL;
var_dump($_POST);
echo '<br><br>Running command.... '.$_POST['command'].PHP_EOL;
echo '<br></p>'.PHP_EOL;
echo '</td></tr></table>';
}
if(isset($_POST['command']))
{
switch(strtolower($_POST['command'])){
case "eject_disk":
action_eject_disk();
break;
case "remove_device":
action_remove_device();
break;
case "connect_new_device":
action_connect_new_device();
break;
case "insert_disk":
action_insert_disk();
break;
case "delete_file":
action_delete_file();
break;
case "create_new_image":
action_create_new_image();
break;
case "restart_rascsi_service":
action_restart_rascsi_service();
break;
case "stop_rascsi_service":
action_stop_rascsi_service();
break;
case "reboot_raspberry_pi":
action_reboot_raspberry_pi();
break;
case "shutdown_raspberry_pi":
action_shutdown_raspberry_pi();
break;
default:
action_unknown_command();
break;
}
}
else{
html_generate_warning("HTTP command was missing POST information. Are you trying to access this page directly? That won't work");
echo "<br>".PHP_EOL;
html_generate_ok_to_go_home();
}
function action_eject_disk(){
$command = 'rasctl -i '.$_POST['id'].' -c eject 2>&1'.PHP_EOL;
exec($command, $retArray, $result);
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
function action_remove_device(){
// Check to see if the user has confirmed
if(isset($_POST['confirmed'])){
$command = 'rasctl -i '.$_POST['id'].' -c disconnect 2>&1'.PHP_EOL;
exec($command, $retArray, $result);
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
else{
check_are_you_sure('Are you sure you want to disconnect SCSI ID ' . $_POST['id'].'? If the host is running, this could cause undesirable behavior.');
}
}
// function action_connect_new_device(){}
function action_insert_disk(){
$command = 'rasctl -i '.$_POST['id'].' -c insert -f '.$GLOBALS['FILE_PATH'].'/'.$_POST['file_name'].' 2>&1'.PHP_EOL;
exec($command, $retArray, $result);
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
function action_create_new_image(){
// If we already know the size & filename, we can go create the image...
if(isset($_POST['size']) && isset($_POST['file_name'])){
$command = 'dd if=/dev/zero of='.$GLOBALS['FILE_PATH'].'/'.$_POST['file_name'].' bs=1M count='.$_POST['size'];
exec($command, $retArray, $result);
check_result($result, $command, $retArray);
html_generate_ok_to_go_home();
}
else{
echo '<h2>Create a new empty file</h2>'.PHP_EOL;
echo '<form action=rascsi_action.php method="post">'.PHP_EOL;
echo ' <input type="hidden" name="command" value="'.$_POST['command'].'"/>'.PHP_EOL;
echo ' <table style="border: none">'.PHP_EOL;
echo ' <tr style="border: none">'.PHP_EOL;
echo ' <td style="border: none">File Name:</td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
echo ' <input type="text" name=file_name value="'.get_new_filename().'"/>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' <td style="border: none"> Size:</td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
echo ' <input type="number" name=size value="10""/>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' <td style="border: none">MB</td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
echo ' <input type="submit" name="create" value="Create New" />'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo ' </table>'.PHP_EOL;
echo '</form>'.PHP_EOL;
echo '<br><i>Note: Creating a large file may take a long time!</i>'.PHP_EOL;
echo '<br><br>'.PHP_EOL;
echo '<form action="rascsi.php" method="post">'.PHP_EOL;
echo ' <input type="submit" name="cancel" value="Cancel" />'.PHP_EOL;
echo '</form>'.PHP_EOL;
}
}
function action_delete_file(){
// Check to see if the user has confirmed
if(isset($_POST['confirmed'])){
$command = 'rm '.$GLOBALS['FILE_PATH'].'/'.$_POST['file_name'];
exec($command, $retArray, $result);
check_result($result, $command, $retArray);
html_generate_ok_to_go_home();
}
else{
check_are_you_sure('Are you sure you want to PERMANENTLY delete '.$_POST['file_name'].'?');
}
}
function action_restart_rascsi_service(){
// Restart the RaSCSI service
$command = "sudo /bin/systemctl restart rascsi.service 2>&1";
exec($command, $retArray, $result);
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
function action_stop_rascsi_service(){
// Stop the RaSCSI service
$command = "sudo /bin/systemctl stop rascsi.service 2>&1";
exec($command, $retArray, $result);
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
function action_reboot_raspberry_pi(){
// Check to see if the user has confirmed
if(isset($_POST['confirmed'])){
$command = "sleep 2 && sudo reboot 2>&1";
exec($command, $retArray, $result);
// The unit should reboot at this point. Doesn't matter what we do now...
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
else{
check_are_you_sure("Are you sure you want to reboot the Raspberry Pi?");
}
}
function action_shutdown_raspberry_pi(){
// Check to see if the user has confirmed
if(isset($_POST['confirmed'])){
$command = "sleep 2 && sudo shutdown -h now 2>&1";
exec($command, $retArray, $result);
// The unit should shutdown at this point. Doesn't matter what we do now...
check_result($result, $command,$retArray);
html_generate_ok_to_go_home();
}
else{
check_are_you_sure("Are you sure you want to shut down the Raspberry Pi?");
}
}
function action_unknown_command(){
html_generate_warning('<br><h2>Unknown command: '.$_POST['command'].'</h2>');
html_generate_ok_to_go_home();
}
function check_result($result,$command,$output){
if(!$result){
html_generate_success_message('Command succeeded!');
}
else{
html_generate_warning('Command failed!');
}
echo '<br><code>'.$command.'</code><br>'.PHP_EOL;
if(count($output) > 0){
echo '<br>Output:<code>'.PHP_EOL;
foreach($output as $line){
echo '<br> Error message: '.$line.PHP_EOL;
}
echo '</code>'.PHP_EOL;
}
}
function check_are_you_sure($prompt){
echo '<br><h2>'.$prompt.'</h2>'.PHP_EOL;
echo ' <table style="border: none">'.PHP_EOL;
echo ' <tr style="border: none">'.PHP_EOL;
echo ' <td style="border: none; vertical-align:top;">'.PHP_EOL;
echo ' <form action="rascsi_action.php" method="post">'.PHP_EOL;
foreach($_POST as $key => $value){
echo '<input type="hidden" name="'.$key.'" value="'.$value.'"/>'.PHP_EOL;
}
echo ' <input type="hidden" name="confirmed" value="yes" />'.PHP_EOL;
echo ' <input type="submit" name="do_it" value="Yes" />'.PHP_EOL;
echo ' </form>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' <td style="border: none; vertical-align:top;">'.PHP_EOL;
echo ' <form action="rascsi.php" method="post">'.PHP_EOL;
echo ' <input type="submit" name="cancel" value="Cancel" />'.PHP_EOL;
echo ' </form>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo '</table>'.PHP_EOL;
}
function action_connect_new_device(){
// If we already know the type & filename, we can go connect the device...
if(isset($_POST['type']) && isset($_POST['file_name'])){
$command = 'rasctl -i '.$_POST['id'].' -c attach -t '.type_string_to_rasctl_type($_POST['type']);
if($_POST['file_name'] != "None"){
$command = $command.' -f '.$GLOBALS['FILE_PATH'].'/'.$_POST['file_name'];
}
exec($command, $retArray, $result);
check_result($result, $command, $retArray);
html_generate_ok_to_go_home();
}
else{
$id = $_POST['id'];
echo '<h2>Add New Device</h2>'.PHP_EOL;
echo '<form action=rascsi_action.php method="post">'.PHP_EOL;
echo ' <input type="hidden" name="command" value="'.$_POST['command'].'"/>'.PHP_EOL;
echo ' <table style="border: none">'.PHP_EOL;
echo ' <tr style="border: none">'.PHP_EOL;
echo ' <td style="border: none">SCSI ID:</td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
echo ' <input type="hidden" name=id value="'.$id.'"/>'.PHP_EOL;
echo $id;
echo ' </td>'.PHP_EOL;
echo ' <td style="border: none">Device:</td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
html_generate_scsi_type_select_list();
echo ' </td>'.PHP_EOL;
echo ' <td style="border: none">File:</td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
echo ' <select name="file_name">'.PHP_EOL;
echo ' <option value="None">None</option>'.PHP_EOL;
html_generate_image_file_select_list();
echo ' </select>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' <td style="border: none">'.PHP_EOL;
echo ' <INPUT type="submit" value="Add"/>'.PHP_EOL;
echo ' </td>'.PHP_EOL;
echo ' </tr>'.PHP_EOL;
echo ' </table>'.PHP_EOL;
}
}
function get_new_filename(){
// Try to find a new file name that doesn't exist.
$i=1;
while(file_exists($GLOBALS['FILE_PATH'].'/'.'new_file'.$i.'.hda'))
{
$i = $i+1;
}
return 'new_file'.$i.'.hda';
}
?>
</body>
</html>

28
src/php/rascsi_styles.css Normal file
View File

@@ -0,0 +1,28 @@
body {
color: black;
background-color: white;
font-family: Arial, Helvetica, sans-serif;
text-decoration:none;
}
h1 {
color: white;
font-size:20px;
background-color:black;
}
h2 {
color: black;
font-size:16px;
margin: 0px;
}
a {
text-decoration: none;
}
table, tr, td {
border: 1px solid black;
border-collapse:collapse;
margin: none;
}

86
src/php/rascsi_upload.php Normal file
View File

@@ -0,0 +1,86 @@
<!-- PHP source code for controlling the RaSCSI - 68kmla edition with a web interface. -->
<!-- Copyright (c) 2020 akuker -->
<!-- Distributed under the BSD-3 Clause License -->
<!DOCTYPE html>
<html>
<head>
<title>RaSCSI Upload Page</title>
<link rel="stylesheet" href="rascsi_styles.css">
</head>
<body>
<?php
include 'lib_rascsi.php';
html_generate_header();
echo '<br>';
if($GLOBALS['DEBUG_ENABLE']){
echo '<table>'.PHP_EOL;
echo ' <tr><td><p style="color:gray">Debug stuff</p></td></tr>'.PHP_EOL;
echo ' <tr><td>';
echo '<p style="color:gray">Post values......................'.PHP_EOL;
echo '<br> '.PHP_EOL;
var_dump($_POST);
echo '<br><br>'.PHP_EOL;
var_dump($_FILES);
echo '<br></p>'.PHP_EOL;
echo '</td></tr></table>';
}
$target_dir = $GLOBALS['FILE_PATH'].'/';
$target_file = $target_dir.basename($_FILES['file_name']['name']);
$upload_ok=1;
$file_type = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
if(isset($_POST['submit']))
{
// Check if file already exists
if ($upload_ok && (file_exists($target_file))) {
html_generate_warning('Error: File '.$target_file.' already exists.');
$upload_ok = 0;
}
// Check file size. Limit is specified in lib_rascsi.php
if ($upload_ok && ($_FILES["file_name"]["size"] > $GLOBALS['MAX_UPLOAD_FILE_SIZE'])) {
html_generate_warning("Error: your file is larger than the maximum size of " . $GLOBALS['MAX_UPLOAD_FILE_SIZE'] . "bytes");
$upload_ok = 0;
}
// Allow certain file formats, also specified in lib_rascsi.php
if($upload_ok && (!in_array(strtolower($file_type),$GLOBALS['ALLOWED_FILE_TYPES']))){
$error_string = 'File type "'. $file_type. '" is not currently allowed.'.
'Only the following file types are allowed: <br>'.
'<ul>'.PHP_EOL;
foreach($GLOBALS['ALLOWED_FILE_TYPES'] as $ft){
$error_string = $error_string. '<li>'.$ft.'</li>'.PHP_EOL;
}
$error_string = $error_string.'</ul>';
$error_string = $error_string.'<br>';
html_generate_warning($error_string);
$upload_ok = 0;
}
//Check if $upload_ok is set to 0 by an error
if ($upload_ok != 0) {
if (move_uploaded_file($_FILES["file_name"]["tmp_name"], $target_file)) {
html_generate_success_message(basename( $_FILES["file_name"]["name"]). " has been uploaded.");
} else {
html_generate_warning("There was an unknown error uploading your file.");
}
}
}
else
{
html_generate_warning('The Submit POST information was not populated. Something went wrong');
}
echo '<br>';
html_generate_ok_to_go_home();
?>
</body>
</html>

44
src/php/status.php Normal file
View File

@@ -0,0 +1,44 @@
<!-- Simple file for showing the status of the RaSCSI process. Intended to be loaded as a frame in a larger page -->
<!-- Copyright (c) 2020 akuker -->
<!-- Distributed under the BSD-3 Clause License -->
<!-- Note: the origina rascsi-php project was under MIT license.-->
<!DOCTYPE html>
<html>
<script type="text/javascript">
window.onload = setupRefresh;
function setupRefresh() {
setTimeout("refreshPage();", 30000); // milliseconds
}
function refreshPage() {
window.location = location.href;
}
</script>
<?php
// Blatently copied from stack overflow:
// https://stackoverflow.com/questions/53695187/php-function-that-shows-status-of-systemctl-service
$output = shell_exec("systemctl is-active rascsi");
if (trim($output) == "active") {
$color='green';
$text='Running';
}
else{
$color='red';
$text='Stopped';
}
echo '<body style="background-color: '.$color.';">';
echo '<table width="100%" height=100% style="position: absolute; top: 0; bottom: 0; left: 0; right: 0; background-color:'.$color.'">';
echo '<tr style:"height: 100%">';
echo '<td style="color: white; background-color: '.$color.'; text-align: center; vertical-align: center; font-family: Arial, Helvetica, sans-serif;">'.$text.' '.date("h:i:sa").'</td>';
echo '</tr>';
echo '</table>';
?>
</body>
</html>

View File

@@ -1,4 +1,3 @@
*.o
*.bak
*.HDA
*.save
@@ -6,9 +5,10 @@
*.layout
*.log
rascsi
scsishark
scsimon
rasctl
sasidump
rasdump
log.*
obj
bin

27
src/raspberrypi/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,27 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/rascsi",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

14
src/raspberrypi/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"files.associations": {
"cstddef": "cpp",
"array": "cpp",
"chrono": "cpp",
"functional": "cpp",
"istream": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp"
}
}

19
src/raspberrypi/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "g++ build active file",
"command": "make",
"args": ["all", "DEBUG=1"],
"options": {
"cwd": "${workspaceFolder}/"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@@ -1,21 +1,43 @@
.DEFAULT_GOAL: all
CC = gcc
CXX = g++
## Optional build flags:
## ARCH=arm : Specify which target platform you're compiling
## for. This will default to arm, which is typical
## on a Raspberry Pi.
## CROSS_COMPILE=arm-linux-gnueabihf- : Specify which compiler
## toolchain to use. This will default to arm-linux-
## gnueabihf-, which is typical on a Raspberry Pi.
## To cross compile on a x86_64 system set these to:
## ARM=x86_64 CROSS_COMPILE=x86_64-linux-gnu-cpp
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
## DEBUG=1 : A Debug build includes the debugger symbols
## and disables compiler optimization. Typically,
## this is only used by developers.
DEBUG ?= 0
ifeq ($(DEBUG), 1)
# Debug CFLAGS
CFLAGS = -DDISK_LOG -O0 -g -Wall -DDEBUG
CXXFLAGS = -DDISK_LOG -O0 -g -Wall -DDEBUG
CFLAGS += -DDISK_LOG -O0 -g -Wall -DDEBUG
CXXFLAGS += -DDISK_LOG -O0 -g -Wall -DDEBUG
BUILD_TYPE = Debug
else
# Release CFLAGS
CFLAGS ?= -O3 -Wall -Werror
CXXFLAGS ?= -O3 -Wall -Werror
CFLAGS += -O3 -Wall -Werror
CXXFLAGS += -O3 -Wall -Werror
BUILD_TYPE = Release
endif
CFLAGS += -iquote . -MD -MP
CXXFLAGS += -std=c++14 -iquote . -MD -MP
## CONNECT_TYPE=STANDARD : Specify the type of RaSCSI board type
## that you are using. The typical options are
## STANDARD or FULLSPEC. The default is STANDARD
## * THIS IS TYPICALLY THE ONLY COMPILE OPTION YOU
## * NEED TO SPECIFY
# If its not specified, build for STANDARD configuration
CONNECT_TYPE ?= STANDARD
@@ -30,25 +52,36 @@ RASDUMP = rasdump
SASIDUMP = sasidump
SCSISHARK = scsishark
SYSTEMD_CONF = /etc/systemd/system/rascsi.service
RSYSLOG_CONF = /etc/rsyslog.d/rascsi.conf
RSYSLOG_LOG = /var/log/rascsi.log
USR_LOCAL_BIN = /usr/local/bin
MAN_PAGE_DIR = /usr/share/man/man1
DOC_DIR = ../../doc
OS_FILES = ./os_integration
OBJDIR := ./obj/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
BINDIR := ./bin/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
#BIN_ALL = $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP) $(SCSIMON)
# Temporarily remove the RASDUMP and RASDUMP tools, since they're not needed
# for my specific use case. If you need them - add them back in!
BIN_ALL = $(RASCSI) $(RASCTL) $(SCSISHARK)
BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL)
SRC_RASCSI = \
rascsi.cpp \
scsi.cpp \
disk.cpp \
gpiobus.cpp \
ctapdriver.cpp \
cfilesystem.cpp \
filepath.cpp \
fileio.cpp
fileio.cpp\
# os.cpp
# rasctl_command.cpp
# rascsi_mgr.cpp
# command_thread.cpp
SRC_RASCSI += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI += $(shell find ./devices -name '*.cpp')
SRC_SCSISHARK = \
scsishark.cpp \
@@ -62,6 +95,7 @@ SRC_SCSISHARK = \
SRC_RASCTL = \
rasctl.cpp
# rasctl_command.cpp
SRC_RASDUMP = \
rasdump.cpp \
@@ -77,19 +111,37 @@ SRC_SASIDUMP = \
filepath.cpp \
fileio.cpp
OBJ_RASCSI := $(SRC_RASCSI:%.cpp=%.o)
OBJ_RASCTL := $(SRC_RASCTL:%.cpp=%.o)
OBJ_RASDUMP := $(SRC_RASDUMP:%.cpp=%.o)
OBJ_SASIDUMP := $(SRC_SASIDUMP:%.cpp=%.o)
OBJ_SCSISHARK := $(SRC_SCSISHARK:%.cpp=%.o)
vpath %.h ./ ./controllers ./devices
vpath %.cpp ./ ./controllers ./devices
vpath %.o ./$(OBJDIR)
vpath ./$(BINDIR)
OBJ_RASCSI := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI:%.cpp=%.o)))
OBJ_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
OBJ_SASIDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SASIDUMP:%.cpp=%.o)))
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
#OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP) $(OBJ_SCSIMON)
OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP) $(OBJ_SCSISHARK)
%.o: %.cpp
# The following will include all of the auto-generated dependency files (*.d)
# if they exist. This will trigger a rebuild of a source file if a header changes
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI) $(OBJ_RASCTL))
-include $(ALL_DEPS)
$(OBJDIR) $(BINDIR):
echo "-- Creating directory $@"
mkdir -p $@
$(OBJDIR)/%.o: %.cpp | $(OBJDIR)
$(CXX) $(CXXFLAGS) -c $< -o $@
## Build Targets:
## all : Rebuild all of the executable files and re-generate
## the text versions of the manpages
## docs : Re-generate the text versions of the man pages
.DEFAULT_GOAL := all
.PHONY: all ALL docs
all: $(BIN_ALL) docs
@@ -97,40 +149,83 @@ ALL: all
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt
$(RASCSI): $(OBJ_RASCSI)
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread
$(RASCTL): $(OBJ_RASCTL)
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL)
$(RASDUMP): $(OBJ_RASDUMP)
$(RASDUMP): $(OBJ_RASDUMP) $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
$(SASIDUMP): $(OBJ_SASIDUMP)
$(SASIDUMP): $(OBJ_SASIDUMP) $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SASIDUMP)
$(SCSISHARK): $(OBJ_SCSISHARK)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSISHARK) -lpthread
$(SCSIMON): $(OBJ_SCSIMON) $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
## clean : Remove all of the object files, intermediate
## compiler files and executable files
.PHONY: clean
clean:
rm -f $(OBJ_ALL) $(BIN_ALL)
rm -rf $(OBJDIR) $(BINDIR)
## run : Launches RaSCSI using some pre-defined drive
## images. Useful for debugging when you're building
## and re-launching over and over.
.PHONY: run
run:
sudo ./$(RASCSI) -ID1 /home/pi/HARDDISK2.hda -ID6 /home/pi/marathon.iso
sudo $(BINDIR)/$(RASCSI) -ID1 /home/pi/HARDDISK2.hda -ID6 /home/pi/marathon.iso
install: $(MAN_PAGE_DIR)/rascsi.1 $(MAN_PAGE_DIR)/rasctl.1
sudo cp $(RASCTL) $(USR_LOCAL_BIN)
sudo cp $(RASCSI) $(USR_LOCAL_BIN)
## install : Copies all of the man pages to the correct location
## Copies the binaries to a global install location
## Configures the Systemd and RSyslog services to auto-run RaSCSI
## * This target needs to be run with sudo (ex: sudo make install)
## * Before running this, you need to stop the rascsi service if
## * it is already running:
## * sudo systemctl stop rascsi
## * After running this, you will need to reboot or run:
## * sudo systemctl daemon-reload
## * sudo systemctl restart rsyslog
## * sudo systemctl enable rascsi
## * sudo systemctl start rascsi
.PHONY: install
install: $(MAN_PAGE_DIR)/rascsi.1 $(MAN_PAGE_DIR)/rasctl.1 $(USR_LOCAL_BIN)/$(RASCTL) $(USR_LOCAL_BIN)/$(RASCSI) $(SYSTEMD_CONF) $(RSYSLOG_CONF) $(RSYSLOG_LOG)
@echo "-- Done installing!"
$(USR_LOCAL_BIN)% : $(BINDIR)/%
@echo "-- Copying $@"
cp $< $@
$(MAN_PAGE_DIR)/%.1 : $(DOC_DIR)/%.1
sudo cp $< $@
@echo "-- Copying $@"
cp $< $@
$(DOC_DIR)/%_man_page.txt : $(DOC_DIR)/%.1
@echo "!! ------ THIS FILE IS AUTO_GENERATED! DO NOT MANUALLY UPDATE!!!" > $@
@echo "!! ------ The native file is $(notdir $<). Re-run 'make docs' after updating\n\n" >> $@
man -l $< | col -bx >> $@
$(SYSTEMD_CONF) : $(OS_FILES)/$(notdir $(SYSTEMD_CONF))
@echo "-- Copying $@"
cp $< $@
$(RSYSLOG_CONF) : $(OS_FILES)/$(notdir $(RSYSLOG_CONF))
@echo "-- Copying $@"
cp $< $@
$(RSYSLOG_LOG) :
@echo "-- Creating $@"
touch /var/log/rascsi.log
chown root:adm /var/log/rascsi.log
## help : Lists information about how to use the makefile
# The help rule is based upon the approach from:
# https://swcarpentry.github.io/make-novice/08-self-doc/index.html
.PHONY: help
help : Makefile
@sed -n 's/^##//p' $<
## Debug : Same as 'all'. Useful when using a debugger.
.PHONY: Debug
Debug: all
.PHONY: Debug-scsishark
Debug-scsishark: $(SCSISHARK)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,211 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SASI device controller ]
//
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include "scsi.h"
#include "fileio.h"
#include "devices/disk.h"
#include "log.h"
#include "xm6.h"
//===========================================================================
//
// SASI Controller
//
//===========================================================================
class SASIDEV
{
public:
// Maximum number of logical units
enum {
UnitMax = 8
};
#ifdef RASCSI
// For timing adjustments
enum {
min_exec_time_sasi = 100, // SASI BOOT/FORMAT 30:NG 35:OK
min_exec_time_scsi = 50
};
#endif // RASCSI
// Internal data definition
typedef struct {
// 全般
BUS::phase_t phase; // Transition phase
int id; // Controller ID (0-7)
BUS *bus; // Bus
// commands
DWORD cmd[10]; // Command data
DWORD status; // Status data
DWORD message; // Message data
#ifdef RASCSI
// Run
DWORD execstart; // Execution start time
#endif // RASCSI
// Transfer
BYTE *buffer; // Transfer data buffer
int bufsize; // Transfer data buffer size
DWORD blocks; // Number of transfer block
DWORD next; // Next record
DWORD offset; // Transfer offset
DWORD length; // Transfer remaining length
// Logical unit
Disk *unit[UnitMax];
// Logical Unit
} ctrl_t;
public:
// Basic Functions
#ifdef RASCSI
SASIDEV();
#else
SASIDEV(Device *dev);
#endif //RASCSI
// Constructor
virtual ~SASIDEV();
// Destructor
virtual void FASTCALL Reset();
// Device Reset
#ifndef RASCSI
virtual BOOL FASTCALL Save(Fileio *fio, int ver);
// Save
virtual BOOL FASTCALL Load(Fileio *fio, int ver);
// Load
#endif //RASCSI
// External API
virtual BUS::phase_t FASTCALL Process();
// Run
// Connect
void FASTCALL Connect(int id, BUS *sbus);
// Controller connection
Disk* FASTCALL GetUnit(int no);
// Get logical unit
void FASTCALL SetUnit(int no, Disk *dev);
// Logical unit setting
BOOL FASTCALL HasUnit();
// Has a valid logical unit
// Other
BUS::phase_t FASTCALL GetPhase() {return ctrl.phase;}
// Get the phase
#ifdef DISK_LOG
// Function to get the current phase as a String.
void FASTCALL GetPhaseStr(char *str);
#endif
int FASTCALL GetID() {return ctrl.id;}
// Get the ID
void FASTCALL GetCTRL(ctrl_t *buffer);
// Get the internal information
ctrl_t* FASTCALL GetWorkAddr() { return &ctrl; }
// Get the internal information address
virtual BOOL FASTCALL IsSASI() const {return TRUE;}
// SASI Check
virtual BOOL FASTCALL IsSCSI() const {return FALSE;}
// SCSI check
Disk* FASTCALL GetBusyUnit();
// Get the busy unit
protected:
// Phase processing
virtual void FASTCALL BusFree();
// Bus free phase
virtual void FASTCALL Selection();
// Selection phase
virtual void FASTCALL Command();
// Command phase
virtual void FASTCALL Execute();
// Execution phase
void FASTCALL Status();
// Status phase
void FASTCALL MsgIn();
// Message in phase
void FASTCALL DataIn();
// Data in phase
void FASTCALL DataOut();
// Data out phase
virtual void FASTCALL Error();
// Common error handling
// commands
void FASTCALL CmdTestUnitReady();
// TEST UNIT READY command
void FASTCALL CmdRezero();
// REZERO UNIT command
void FASTCALL CmdRequestSense();
// REQUEST SENSE command
void FASTCALL CmdFormat();
// FORMAT command
void FASTCALL CmdReassign();
// REASSIGN BLOCKS command
void FASTCALL CmdRead6();
// READ(6) command
void FASTCALL CmdWrite6();
// WRITE(6) command
void FASTCALL CmdSeek6();
// SEEK(6) command
void FASTCALL CmdAssign();
// ASSIGN command
void FASTCALL CmdSpecify();
// SPECIFY command
void FASTCALL CmdInvalid();
// Unsupported command
// データ転送
virtual void FASTCALL Send();
// Send data
#ifndef RASCSI
virtual void FASTCALL SendNext();
// Continue sending data
#endif // RASCSI
virtual void FASTCALL Receive();
// Receive data
#ifndef RASCSI
virtual void FASTCALL ReceiveNext();
// Continue receiving data
#endif // RASCSI
BOOL FASTCALL XferIn(BYTE* buf);
// Data transfer IN
BOOL FASTCALL XferOut(BOOL cont);
// Data transfer OUT
// Special operations
void FASTCALL FlushUnit();
// Flush the logical unit
// Log
void FASTCALL Log(Log::loglevel level, const char *format, ...);
// Log output
protected:
#ifndef RASCSI
Device *host;
// Host device
#endif // RASCSI
ctrl_t ctrl;
// Internal data
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI device controller ]
//
//---------------------------------------------------------------------------
#pragma once
#include "controllers/sasidev_ctrl.h"
//===========================================================================
//
// SCSI Device (Interits SASI device)
//
//===========================================================================
class SCSIDEV : public SASIDEV
{
public:
// Internal data definition
typedef struct {
// Synchronous transfer
BOOL syncenable; // Synchronous transfer possible
int syncperiod; // Synchronous transfer period
int syncoffset; // Synchronous transfer offset
int syncack; // Number of synchronous transfer ACKs
// ATN message
BOOL atnmsg;
int msc;
BYTE msb[256];
} scsi_t;
public:
// Basic Functions
#ifdef RASCSI
SCSIDEV();
#else
SCSIDEV(Device *dev);
#endif // RASCSI
// Constructor
void FASTCALL Reset();
// Device Reset
// 外部API
BUS::phase_t FASTCALL Process();
// Run
void FASTCALL SyncTransfer(BOOL enable) { scsi.syncenable = enable; }
// Synchronouse transfer enable setting
// Other
BOOL FASTCALL IsSASI() const {return FALSE;}
// SASI Check
BOOL FASTCALL IsSCSI() const {return TRUE;}
// SCSI check
private:
// Phase
void FASTCALL BusFree();
// Bus free phase
void FASTCALL Selection();
// Selection phase
void FASTCALL Execute();
// Execution phase
void FASTCALL MsgOut();
// Message out phase
void FASTCALL Error();
// Common erorr handling
// commands
void FASTCALL CmdInquiry();
// INQUIRY command
void FASTCALL CmdModeSelect();
// MODE SELECT command
void FASTCALL CmdModeSense();
// MODE SENSE command
void FASTCALL CmdStartStop();
// START STOP UNIT command
void FASTCALL CmdSendDiag();
// SEND DIAGNOSTIC command
void FASTCALL CmdRemoval();
// PREVENT/ALLOW MEDIUM REMOVAL command
void FASTCALL CmdReadCapacity();
// READ CAPACITY command
void FASTCALL CmdRead10();
// READ(10) command
void FASTCALL CmdWrite10();
// WRITE(10) command
void FASTCALL CmdSeek10();
// SEEK(10) command
void FASTCALL CmdVerify();
// VERIFY command
void FASTCALL CmdSynchronizeCache();
// SYNCHRONIZE CACHE command
void FASTCALL CmdReadDefectData10();
// READ DEFECT DATA(10) command
void FASTCALL CmdReadToc();
// READ TOC command
void FASTCALL CmdPlayAudio10();
// PLAY AUDIO(10) command
void FASTCALL CmdPlayAudioMSF();
// PLAY AUDIO MSF command
void FASTCALL CmdPlayAudioTrack();
// PLAY AUDIO TRACK INDEX command
void FASTCALL CmdModeSelect10();
// MODE SELECT(10) command
void FASTCALL CmdModeSense10();
// MODE SENSE(10) command
void FASTCALL CmdGetMessage10();
// GET MESSAGE(10) command
void FASTCALL CmdSendMessage10();
// SEND MESSAGE(10) command
// データ転送
void FASTCALL Send();
// Send data
#ifndef RASCSI
void FASTCALL SendNext();
// Continue sending data
#endif // RASCSI
void FASTCALL Receive();
// Receive data
#ifndef RASCSI
void FASTCALL ReceiveNext();
// Continue receiving data
#endif // RASCSI
BOOL FASTCALL XferMsg(DWORD msg);
// Data transfer message
scsi_t scsi;
// Internal data
};

View File

@@ -76,6 +76,7 @@ static void convert(char const *src, char const *dest,
const char *inbuf, char *outbuf, size_t outsize)
#endif
{
#ifndef __APPLE__
iconv_t cd;
size_t in;
size_t out;
@@ -97,6 +98,7 @@ static void convert(char const *src, char const *dest,
iconv_close(cd);
*outbuf = '\0';
#endif //ifndef __macintosh__
}
#else
// Newlibの中にiconvが含まれてなかったので無変換
@@ -4548,7 +4550,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
case 2:
switch (pIoctrl->param) {
case -1:
case (DWORD)-1:
// メディア再認識
m_cEntry.isMediaOffline(nUnit);
return 0;
@@ -4560,17 +4562,17 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
}
break;
case -1:
case (DWORD)-1:
// 常駐判定
memcpy(pIoctrl->buffer, "WindrvXM", 8);
return 0;
case -2:
case (DWORD)-2:
// オプション設定
SetOption(pIoctrl->param);
return 0;
case -3:
case (DWORD)-3:
// オプション獲得
pIoctrl->param = GetOption();
return 0;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,368 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
//
// XM6i
// Copyright (C) 2010-2015 isaki@NetBSD.org
//
// Imported sava's Anex86/T98Next image and MO format support patch.
// Comments translated to english by akuker.
//
// [ Disk ]
//
//---------------------------------------------------------------------------
#pragma once
#include "xm6.h"
#include "log.h"
#include "scsi.h"
#include "filepath.h"
//---------------------------------------------------------------------------
//
// Error definition (sense code returned by REQUEST SENSE)
//
// MSB Reserved (0x00)
// Sense Key
// Additional Sense Code (ASC)
// LSB Additional Sense Code Qualifier(ASCQ)
//
//---------------------------------------------------------------------------
#define DISK_NOERROR 0x00000000 // NO ADDITIONAL SENSE INFO.
#define DISK_DEVRESET 0x00062900 // POWER ON OR RESET OCCURED
#define DISK_NOTREADY 0x00023a00 // MEDIUM NOT PRESENT
#define DISK_ATTENTION 0x00062800 // MEDIUM MAY HAVE CHANGED
#define DISK_PREVENT 0x00045302 // MEDIUM REMOVAL PREVENTED
#define DISK_READFAULT 0x00031100 // UNRECOVERED READ ERROR
#define DISK_WRITEFAULT 0x00030300 // PERIPHERAL DEVICE WRITE FAULT
#define DISK_WRITEPROTECT 0x00042700 // WRITE PROTECTED
#define DISK_MISCOMPARE 0x000e1d00 // MISCOMPARE DURING VERIFY
#define DISK_INVALIDCMD 0x00052000 // INVALID COMMAND OPERATION CODE
#define DISK_INVALIDLBA 0x00052100 // LOGICAL BLOCK ADDR. OUT OF RANGE
#define DISK_INVALIDCDB 0x00052400 // INVALID FIELD IN CDB
#define DISK_INVALIDLUN 0x00052500 // LOGICAL UNIT NOT SUPPORTED
#define DISK_INVALIDPRM 0x00052600 // INVALID FIELD IN PARAMETER LIST
#define DISK_INVALIDMSG 0x00054900 // INVALID MESSAGE ERROR
#define DISK_PARAMLEN 0x00051a00 // PARAMETERS LIST LENGTH ERROR
#define DISK_PARAMNOT 0x00052601 // PARAMETERS NOT SUPPORTED
#define DISK_PARAMVALUE 0x00052602 // PARAMETERS VALUE INVALID
#define DISK_PARAMSAVE 0x00053900 // SAVING PARAMETERS NOT SUPPORTED
#define DISK_NODEFECT 0x00010000 // DEFECT LIST NOT FOUND
#if 0
#define DISK_AUDIOPROGRESS 0x00??0011 // AUDIO PLAY IN PROGRESS
#define DISK_AUDIOPAUSED 0x00??0012 // AUDIO PLAY PAUSED
#define DISK_AUDIOSTOPPED 0x00??0014 // AUDIO PLAY STOPPED DUE TO ERROR
#define DISK_AUDIOCOMPLETE 0x00??0013 // AUDIO PLAY SUCCESSFULLY COMPLETED
#endif
#ifdef RASCSI
#define BENDER_SIGNATURE "RaSCSI"
// The following line was to mimic Apple's CDROM ID
// #define BENDER_SIGNATURE "SONY "
#else
#define BENDER_SIGNATURE "XM6"
#endif
//===========================================================================
//
// Disk Track
//
//===========================================================================
class DiskTrack
{
public:
// Internal data definition
typedef struct {
int track; // Track Number
int size; // Sector Size(8 or 9)
int sectors; // Number of sectors(<=0x100)
DWORD length; // Data buffer length
BYTE *buffer; // Data buffer
BOOL init; // Is it initilized?
BOOL changed; // Changed flag
DWORD maplen; // Changed map length
BOOL *changemap; // Changed map
BOOL raw; // RAW mode flag
off64_t imgoffset; // Offset to actual data
} disktrk_t;
public:
// Basic Functions
DiskTrack();
// Constructor
virtual ~DiskTrack();
// Destructor
void FASTCALL Init(int track, int size, int sectors, BOOL raw = FALSE,
off64_t imgoff = 0);
// Initialization
BOOL FASTCALL Load(const Filepath& path);
// Load
BOOL FASTCALL Save(const Filepath& path);
// Save
// Read / Write
BOOL FASTCALL Read(BYTE *buf, int sec) const;
// Sector Read
BOOL FASTCALL Write(const BYTE *buf, int sec);
// Sector Write
// Other
int FASTCALL GetTrack() const { return dt.track; }
// Get track
BOOL FASTCALL IsChanged() const { return dt.changed; }
// Changed flag check
private:
// Internal data
disktrk_t dt;
// Internal data
};
//===========================================================================
//
// Disk Cache
//
//===========================================================================
class DiskCache
{
public:
// Internal data definition
typedef struct {
DiskTrack *disktrk; // Disk Track
DWORD serial; // Serial
} cache_t;
// Number of caches
enum {
CacheMax = 16 // Number of tracks to cache
};
public:
// Basic Functions
DiskCache(const Filepath& path, int size, int blocks,
off64_t imgoff = 0);
// Constructor
virtual ~DiskCache();
// Destructor
void FASTCALL SetRawMode(BOOL raw);
// CD-ROM raw mode setting
// Access
BOOL FASTCALL Save();
// Save and release all
BOOL FASTCALL Read(BYTE *buf, int block);
// Sector Read
BOOL FASTCALL Write(const BYTE *buf, int block);
// Sector Write
BOOL FASTCALL GetCache(int index, int& track, DWORD& serial) const;
// Get cache information
private:
// Internal Management
void FASTCALL Clear();
// Clear all tracks
DiskTrack* FASTCALL Assign(int track);
// Load track
BOOL FASTCALL Load(int index, int track, DiskTrack *disktrk = NULL);
// Load track
void FASTCALL Update();
// Update serial number
// Internal data
cache_t cache[CacheMax];
// Cache management
DWORD serial;
// Last serial number
Filepath sec_path;
// Path
int sec_size;
// Sector size (8 or 9 or 11)
int sec_blocks;
// Blocks per sector
BOOL cd_raw;
// CD-ROM RAW mode
off64_t imgoffset;
// Offset to actual data
};
//===========================================================================
//
// Disk
//
//===========================================================================
class Disk
{
public:
// Internal data structure
typedef struct {
DWORD id; // Media ID
BOOL ready; // Valid Disk
BOOL writep; // Write protected
BOOL readonly; // Read only
BOOL removable; // Removable
BOOL lock; // Locked
BOOL attn; // Attention
BOOL reset; // Reset
int size; // Sector Size
DWORD blocks; // Total number of sectors
DWORD lun; // LUN
DWORD code; // Status code
DiskCache *dcache; // Disk cache
off64_t imgoffset; // Offset to actual data
} disk_t;
public:
// Basic Functions
Disk();
// Constructor
virtual ~Disk();
// Destructor
virtual void FASTCALL Reset();
// Device Reset
#ifndef RASCSI
virtual BOOL FASTCALL Save(Fileio *fio, int ver);
// Save
virtual BOOL FASTCALL Load(Fileio *fio, int ver);
// Load
#endif // RASCSI
// ID
DWORD FASTCALL GetID() const { return disk.id; }
// Get media ID
BOOL FASTCALL IsNULL() const;
// NULL check
BOOL FASTCALL IsSASI() const;
// SASI Check
BOOL FASTCALL IsSCSI() const;
// SASI Check
// Media Operations
virtual BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE);
// Open
void FASTCALL GetPath(Filepath& path) const;
// Get the path
void FASTCALL Eject(BOOL force);
// Eject
BOOL FASTCALL IsReady() const { return disk.ready; }
// Ready check
void FASTCALL WriteP(BOOL flag);
// Set Write Protect flag
BOOL FASTCALL IsWriteP() const { return disk.writep; }
// Get write protect flag
BOOL FASTCALL IsReadOnly() const { return disk.readonly; }
// Get read only flag
BOOL FASTCALL IsRemovable() const { return disk.removable; }
// Get is removable flag
BOOL FASTCALL IsLocked() const { return disk.lock; }
// Get locked status
BOOL FASTCALL IsAttn() const { return disk.attn; }
// Get attention flag
BOOL FASTCALL Flush();
// Flush the cache
void FASTCALL GetDisk(disk_t *buffer) const;
// Get the internal data struct
// Properties
void FASTCALL SetLUN(DWORD lun) { disk.lun = lun; }
// LUN set
DWORD FASTCALL GetLUN() { return disk.lun; }
// LUN get
// commands
virtual int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
virtual int FASTCALL RequestSense(const DWORD *cdb, BYTE *buf);
// REQUEST SENSE command
int FASTCALL SelectCheck(const DWORD *cdb);
// SELECT check
int FASTCALL SelectCheck10(const DWORD *cdb);
// SELECT(10) check
virtual BOOL FASTCALL ModeSelect(const DWORD *cdb, const BYTE *buf, int length);
// MODE SELECT command
virtual int FASTCALL ModeSense(const DWORD *cdb, BYTE *buf);
// MODE SENSE command
virtual int FASTCALL ModeSense10(const DWORD *cdb, BYTE *buf);
// MODE SENSE(10) command
int FASTCALL ReadDefectData10(const DWORD *cdb, BYTE *buf);
// READ DEFECT DATA(10) command
virtual BOOL FASTCALL TestUnitReady(const DWORD *cdb);
// TEST UNIT READY command
BOOL FASTCALL Rezero(const DWORD *cdb);
// REZERO command
BOOL FASTCALL Format(const DWORD *cdb);
// FORMAT UNIT command
BOOL FASTCALL Reassign(const DWORD *cdb);
// REASSIGN UNIT command
virtual int FASTCALL Read(BYTE *buf, DWORD block);
// READ command
int FASTCALL WriteCheck(DWORD block);
// WRITE check
BOOL FASTCALL Write(const BYTE *buf, DWORD block);
// WRITE command
BOOL FASTCALL Seek(const DWORD *cdb);
// SEEK command
BOOL FASTCALL Assign(const DWORD *cdb);
// ASSIGN command
BOOL FASTCALL Specify(const DWORD *cdb);
// SPECIFY command
BOOL FASTCALL StartStop(const DWORD *cdb);
// START STOP UNIT command
BOOL FASTCALL SendDiag(const DWORD *cdb);
// SEND DIAGNOSTIC command
BOOL FASTCALL Removal(const DWORD *cdb);
// PREVENT/ALLOW MEDIUM REMOVAL command
int FASTCALL ReadCapacity(const DWORD *cdb, BYTE *buf);
// READ CAPACITY command
BOOL FASTCALL Verify(const DWORD *cdb);
// VERIFY command
virtual int FASTCALL ReadToc(const DWORD *cdb, BYTE *buf);
// READ TOC command
virtual BOOL FASTCALL PlayAudio(const DWORD *cdb);
// PLAY AUDIO command
virtual BOOL FASTCALL PlayAudioMSF(const DWORD *cdb);
// PLAY AUDIO MSF command
virtual BOOL FASTCALL PlayAudioTrack(const DWORD *cdb);
// PLAY AUDIO TRACK command
void FASTCALL InvalidCmd() { disk.code = DISK_INVALIDCMD; }
// Unsupported command
// Other
BOOL IsCacheWB() { return cache_wb; }
// Get cache writeback mode
void SetCacheWB(BOOL enable) { cache_wb = enable; }
// Set cache writeback mode
protected:
// Internal processing
virtual int FASTCALL AddError(BOOL change, BYTE *buf);
// Add error
virtual int FASTCALL AddFormat(BOOL change, BYTE *buf);
// Add format
virtual int FASTCALL AddDrive(BOOL change, BYTE *buf);
// Add drive
int FASTCALL AddOpt(BOOL change, BYTE *buf);
// Add optical
int FASTCALL AddCache(BOOL change, BYTE *buf);
// Add cache
int FASTCALL AddCDROM(BOOL change, BYTE *buf);
// Add CD-ROM
int FASTCALL AddCDDA(BOOL change, BYTE *buf);
// Add CD_DA
virtual int FASTCALL AddVendor(int page, BOOL change, BYTE *buf);
// Add vendor special info
BOOL FASTCALL CheckReady();
// Check if ready
// Internal data
disk_t disk;
// Internal disk data
Filepath diskpath;
// File path (for GetPath)
BOOL cache_wb;
// Cache mode
};

View File

@@ -0,0 +1,164 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SASI hard disk ]
//
//---------------------------------------------------------------------------
#include "sasihd.h"
#include "xm6.h"
#include "fileio.h"
//===========================================================================
//
// SASI Hard Disk
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SASIHD::SASIHD() : Disk()
{
// SASI ハードディスク
disk.id = MAKEID('S', 'A', 'H', 'D');
}
//---------------------------------------------------------------------------
//
// リセット
//
//---------------------------------------------------------------------------
void FASTCALL SASIHD::Reset()
{
// ロック状態解除、アテンション解除
disk.lock = FALSE;
disk.attn = FALSE;
// Resetなし、コードをクリア
disk.reset = FALSE;
disk.code = 0x00;
}
//---------------------------------------------------------------------------
//
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL SASIHD::Open(const Filepath& path, BOOL /*attn*/)
{
Fileio fio;
off64_t size;
ASSERT(this);
ASSERT(!disk.ready);
// Open as read-only
if (!fio.Open(path, Fileio::ReadOnly)) {
return FALSE;
}
// Get file size
size = fio.GetFileSize();
fio.Close();
#if defined(USE_MZ1F23_1024_SUPPORT)
// MZ-2500/MZ-2800用 MZ-1F23(SASI 20M/セクタサイズ1024)専用
// 20M(22437888 BS=1024 C=21912)
if (size == 0x1566000) {
// セクタサイズとブロック数
disk.size = 10;
disk.blocks = (DWORD)(size >> 10);
// Call the base class
return Disk::Open(path);
}
#endif // USE_MZ1F23_1024_SUPPORT
#if defined(REMOVE_FIXED_SASIHD_SIZE)
// 256バイト単位であること
if (size & 0xff) {
return FALSE;
}
// 10MB以上
if (size < 0x9f5400) {
return FALSE;
}
// 512MB程度に制限しておく
if (size > 512 * 1024 * 1024) {
return FALSE;
}
#else
// 10MB, 20MB, 40MBのみ
switch (size) {
// 10MB(10441728 BS=256 C=40788)
case 0x9f5400:
break;
// 20MB(20748288 BS=256 C=81048)
case 0x13c9800:
break;
// 40MB(41496576 BS=256 C=162096)
case 0x2793000:
break;
// Other(サポートしない)
default:
return FALSE;
}
#endif // REMOVE_FIXED_SASIHD_SIZE
// セクタサイズとブロック数
disk.size = 8;
disk.blocks = (DWORD)(size >> 8);
// Call the base class
return Disk::Open(path);
}
//---------------------------------------------------------------------------
//
// REQUEST SENSE
//
//---------------------------------------------------------------------------
int FASTCALL SASIHD::RequestSense(const DWORD *cdb, BYTE *buf)
{
int size;
ASSERT(this);
ASSERT(cdb);
ASSERT(buf);
// サイズ決定
size = (int)cdb[4];
ASSERT((size >= 0) && (size < 0x100));
// サイズ0のときに4バイト転送する(Shugart Associates System Interface仕様)
if (size == 0) {
size = 4;
}
// SASIは非拡張フォーマットに固定
memset(buf, 0, size);
buf[0] = (BYTE)(disk.code >> 16);
buf[1] = (BYTE)(disk.lun << 5);
// コードをクリア
disk.code = 0x00;
return size;
}

View File

@@ -0,0 +1,40 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SASI hard disk ]
//
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include "disk.h"
#include "filepath.h"
//===========================================================================
//
// SASI Hard Disk
//
//===========================================================================
class SASIHD : public Disk
{
public:
// Basic Functions
SASIHD();
// Constructor
void FASTCALL Reset();
// Reset
BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE);
// Open
// commands
int FASTCALL RequestSense(const DWORD *cdb, BYTE *buf);
// REQUEST SENSE command
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Host Bridge for the Sharp X68000 ]
//
// Note: This requires a special driver on the host system and will only
// work with the Sharp X68000 operating system.
//---------------------------------------------------------------------------
#pragma once
#include "xm6.h"
#include "os.h"
#include "disk.h"
//===========================================================================
//
// SCSI Host Bridge
//
//===========================================================================
#if defined(RASCSI) && !defined(BAREMETAL)
class CTapDriver;
#endif // RASCSI && !BAREMETAL
class CFileSys;
class SCSIBR : public Disk
{
public:
// Basic Functions
SCSIBR();
// Constructor
virtual ~SCSIBR();
// Destructor
// commands
int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
BOOL FASTCALL TestUnitReady(const DWORD *cdb);
// TEST UNIT READY command
int FASTCALL GetMessage10(const DWORD *cdb, BYTE *buf);
// GET MESSAGE10 command
BOOL FASTCALL SendMessage10(const DWORD *cdb, BYTE *buf);
// SEND MESSAGE10 command
private:
#if defined(RASCSI) && !defined(BAREMETAL)
int FASTCALL GetMacAddr(BYTE *buf);
// Get MAC address
void FASTCALL SetMacAddr(BYTE *buf);
// Set MAC address
void FASTCALL ReceivePacket();
// Receive a packet
void FASTCALL GetPacketBuf(BYTE *buf);
// Get a packet
void FASTCALL SendPacket(BYTE *buf, int len);
// Send a packet
CTapDriver *tap;
// TAP driver
BOOL m_bTapEnable;
// TAP valid flag
BYTE mac_addr[6];
// MAC Addres
int packet_len;
// Receive packet size
BYTE packet_buf[0x1000];
// Receive packet buffer
BOOL packet_enable;
// Received packet valid
#endif // RASCSI && !BAREMETAL
int FASTCALL ReadFsResult(BYTE *buf);
// Read filesystem (result code)
int FASTCALL ReadFsOut(BYTE *buf);
// Read filesystem (return data)
int FASTCALL ReadFsOpt(BYTE *buf);
// Read file system (optional data)
void FASTCALL WriteFs(int func, BYTE *buf);
// File system write (execute)
void FASTCALL WriteFsOpt(BYTE *buf, int len);
// File system write (optional data)
// Command handlers
void FASTCALL FS_InitDevice(BYTE *buf);
// $40 - boot
void FASTCALL FS_CheckDir(BYTE *buf);
// $41 - directory check
void FASTCALL FS_MakeDir(BYTE *buf);
// $42 - create directory
void FASTCALL FS_RemoveDir(BYTE *buf);
// $43 - delete directory
void FASTCALL FS_Rename(BYTE *buf);
// $44 - change filename
void FASTCALL FS_Delete(BYTE *buf);
// $45 - delete file
void FASTCALL FS_Attribute(BYTE *buf);
// $46 - get/set file attributes
void FASTCALL FS_Files(BYTE *buf);
// $47 - file search
void FASTCALL FS_NFiles(BYTE *buf);
// $48 - find next file
void FASTCALL FS_Create(BYTE *buf);
// $49 - create file
void FASTCALL FS_Open(BYTE *buf);
// $4A - open file
void FASTCALL FS_Close(BYTE *buf);
// $4B - close file
void FASTCALL FS_Read(BYTE *buf);
// $4C - read file
void FASTCALL FS_Write(BYTE *buf);
// $4D - write file
void FASTCALL FS_Seek(BYTE *buf);
// $4E - seek file
void FASTCALL FS_TimeStamp(BYTE *buf);
// $4F - get/set file time
void FASTCALL FS_GetCapacity(BYTE *buf);
// $50 - get capacity
void FASTCALL FS_CtrlDrive(BYTE *buf);
// $51 - drive status check/control
void FASTCALL FS_GetDPB(BYTE *buf);
// $52 - get DPB
void FASTCALL FS_DiskRead(BYTE *buf);
// $53 - read sector
void FASTCALL FS_DiskWrite(BYTE *buf);
// $54 - write sector
void FASTCALL FS_Ioctrl(BYTE *buf);
// $55 - IOCTRL
void FASTCALL FS_Flush(BYTE *buf);
// $56 - flush cache
void FASTCALL FS_CheckMedia(BYTE *buf);
// $57 - check media
void FASTCALL FS_Lock(BYTE *buf);
// $58 - get exclusive control
CFileSys *fs;
// File system accessor
DWORD fsresult;
// File system access result code
BYTE fsout[0x800];
// File system access result buffer
DWORD fsoutlen;
// File system access result buffer size
BYTE fsopt[0x1000000];
// File system access buffer
DWORD fsoptlen;
// File system access buffer size
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Hard Disk for Apple Macintosh ]
//
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include "disk.h"
#include "filepath.h"
//---------------------------------------------------------------------------
//
// Class precedence definition
//
//---------------------------------------------------------------------------
class SCSICD;
//===========================================================================
//
// CD-ROM Track
//
//===========================================================================
class CDTrack
{
public:
// Basic Functions
CDTrack(SCSICD *scsicd);
// Constructor
virtual ~CDTrack();
// Destructor
BOOL FASTCALL Init(int track, DWORD first, DWORD last);
// Initialization
// Properties
void FASTCALL SetPath(BOOL cdda, const Filepath& path);
// Set the path
void FASTCALL GetPath(Filepath& path) const;
// Get the path
void FASTCALL AddIndex(int index, DWORD lba);
// Add index
DWORD FASTCALL GetFirst() const;
// Get the start LBA
DWORD FASTCALL GetLast() const;
// Get the last LBA
DWORD FASTCALL GetBlocks() const;
// Get the number of blocks
int FASTCALL GetTrackNo() const;
// Get the track number
BOOL FASTCALL IsValid(DWORD lba) const;
// Is this a valid LBA?
BOOL FASTCALL IsAudio() const;
// Is this an audio track?
private:
SCSICD *cdrom;
// Parent device
BOOL valid;
// Valid track
int track_no;
// Track number
DWORD first_lba;
// First LBA
DWORD last_lba;
// Last LBA
BOOL audio;
// Audio track flag
BOOL raw;
// RAW data flag
Filepath imgpath;
// Image file path
};
//===========================================================================
//
// CD-DA Buffer
//
//===========================================================================
class CDDABuf
{
public:
// Basic Functions
CDDABuf();
// Constructor
virtual ~CDDABuf();
// Destructor
#if 0
BOOL Init();
// Initialization
BOOL FASTCALL Load(const Filepath& path);
// Load
BOOL FASTCALL Save(const Filepath& path);
// Save
// API
void FASTCALL Clear();
// Clear the buffer
BOOL FASTCALL Open(Filepath& path);
// File specification
BOOL FASTCALL GetBuf(DWORD *buffer, int frames);
// Get the buffer
BOOL FASTCALL IsValid();
// Check if Valid
BOOL FASTCALL ReadReq();
// Read Request
BOOL FASTCALL IsEnd() const;
// Finish check
private:
Filepath wavepath;
// Wave path
BOOL valid;
// Open result (is it valid?)
DWORD *buf;
// Data buffer
DWORD read;
// Read pointer
DWORD write;
// Write pointer
DWORD num;
// Valid number of data
DWORD rest;
// Remaining file size
#endif
};
//===========================================================================
//
// SCSI CD-ROM
//
//===========================================================================
class SCSICD : public Disk
{
public:
// Number of tracks
enum {
TrackMax = 96 // Maximum number of tracks
};
public:
// Basic Functions
SCSICD();
// Constructor
virtual ~SCSICD();
// Destructor
BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE);
// Open
#ifndef RASCSI
BOOL FASTCALL Load(Fileio *fio, int ver);
// Load
#endif // RASCSI
// commands
int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
int FASTCALL Read(BYTE *buf, DWORD block);
// READ command
int FASTCALL ReadToc(const DWORD *cdb, BYTE *buf);
// READ TOC command
BOOL FASTCALL PlayAudio(const DWORD *cdb);
// PLAY AUDIO command
BOOL FASTCALL PlayAudioMSF(const DWORD *cdb);
// PLAY AUDIO MSF command
BOOL FASTCALL PlayAudioTrack(const DWORD *cdb);
// PLAY AUDIO TRACK command
// CD-DA
BOOL FASTCALL NextFrame();
// Frame notification
void FASTCALL GetBuf(DWORD *buffer, int samples, DWORD rate);
// Get CD-DA buffer
// LBA-MSF変換
void FASTCALL LBAtoMSF(DWORD lba, BYTE *msf) const;
// LBA→MSF conversion
DWORD FASTCALL MSFtoLBA(const BYTE *msf) const;
// MSF→LBA conversion
private:
// Open
BOOL FASTCALL OpenCue(const Filepath& path);
// Open(CUE)
BOOL FASTCALL OpenIso(const Filepath& path);
// Open(ISO)
BOOL FASTCALL OpenPhysical(const Filepath& path);
// Open(Physical)
BOOL rawfile;
// RAW flag
// Track management
void FASTCALL ClearTrack();
// Clear the track
int FASTCALL SearchTrack(DWORD lba) const;
// Track search
CDTrack* track[TrackMax];
// Track opbject references
int tracks;
// Effective number of track objects
int dataindex;
// Current data track
int audioindex;
// Current audio track
int frame;
// Frame number
#if 0
CDDABuf da_buf;
// CD-DA buffer
int da_num;
// Number of CD-DA tracks
int da_cur;
// CD-DA current track
int da_next;
// CD-DA next track
BOOL da_req;
// CD-DA data request
#endif
};

View File

@@ -0,0 +1,268 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI hard disk ]
//
//---------------------------------------------------------------------------
#include "scsihd.h"
#include "xm6.h"
#include "fileio.h"
//===========================================================================
//
// SCSI Hard Disk
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIHD::SCSIHD() : Disk()
{
// SCSI Hard Disk
disk.id = MAKEID('S', 'C', 'H', 'D');
}
//---------------------------------------------------------------------------
//
// Reset
//
//---------------------------------------------------------------------------
void FASTCALL SCSIHD::Reset()
{
// Unlock and release attention
disk.lock = FALSE;
disk.attn = FALSE;
// No reset, clear code
disk.reset = FALSE;
disk.code = 0x00;
}
//---------------------------------------------------------------------------
//
// Open
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
{
Fileio fio;
off64_t size;
ASSERT(this);
ASSERT(!disk.ready);
// read open required
if (!fio.Open(path, Fileio::ReadOnly)) {
return FALSE;
}
// Get file size
size = fio.GetFileSize();
fio.Close();
// Must be 512 bytes
if (size & 0x1ff) {
return FALSE;
}
// 10MB or more
if (size < 0x9f5400) {
return FALSE;
}
// 2TB according to xm6i
// There is a similar one in wxw/wxw_cfg.cpp
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
return FALSE;
}
// sector size and number of blocks
disk.size = 9;
disk.blocks = (DWORD)(size >> 9);
// Call base class
return Disk::Open(path);
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
char vendor[32];
char product[32];
char rev[32];
int size;
ASSERT(this);
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
return 0;
}
// Ready check (Error if no image file)
if (!disk.ready) {
disk.code = DISK_NOTREADY;
return 0;
}
// Basic data
// buf[0] ... Direct Access Device
// buf[2] ... SCSI-2 compliant command system
// buf[3] ... SCSI-2 compliant Inquiry response
// buf[4] ... Inquiry additional data
memset(buf, 0, 8);
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
buf[0] = 0x7f;
}
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 122 + 3; // Value close to real HDD
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Determine vendor name/product name
sprintf(vendor, BENDER_SIGNATURE);
size = disk.blocks >> 11;
if (size < 300)
sprintf(product, "PRODRIVE LPS%dS", size);
else if (size < 600)
sprintf(product, "MAVERICK%dS", size);
else if (size < 800)
sprintf(product, "LIGHTNING%dS", size);
else if (size < 1000)
sprintf(product, "TRAILBRAZER%dS", size);
else if (size < 2000)
sprintf(product, "FIREBALL%dS", size);
else
sprintf(product, "FBSE%d.%dS", size / 1000, (size % 1000) / 100);
// Vendor name
memcpy(&buf[8], vendor, strlen(vendor));
// Product name
memcpy(&buf[16], product, strlen(product));
// Revision
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
// Size of data that can be returned
size = (buf[4] + 5);
// Limit if the other buffer is small
if (size > (int)cdb[4]) {
size = (int)cdb[4];
}
// Success
disk.code = DISK_NOERROR;
return size;
}
//---------------------------------------------------------------------------
//
// MODE SELECT
// *Not affected by disk.code
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
BYTE page;
int size;
ASSERT(this);
ASSERT(buf);
ASSERT(length >= 0);
// PF
if (cdb[1] & 0x10) {
// Mode Parameter header
if (length >= 12) {
// Check the block length bytes
size = 1 << disk.size;
if (buf[9] != (BYTE)(size >> 16) ||
buf[10] != (BYTE)(size >> 8) ||
buf[11] != (BYTE)size) {
// currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
}
buf += 12;
length -= 12;
}
// Parsing the page
while (length > 0) {
// Get page
page = buf[0];
switch (page) {
// format device
case 0x03:
// check the number of bytes in the physical sector
size = 1 << disk.size;
if (buf[0xc] != (BYTE)(size >> 8) ||
buf[0xd] != (BYTE)size) {
// currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
}
break;
// CD-ROM Parameters
// According to the SONY CDU-541 manual, Page code 8 is supposed
// to set the Logical Block Adress Format, as well as the
// inactivity timer multiplier
case 0x08:
// Debug code for Issue #2:
// https://github.com/akuker/RASCSI/issues/2
printf("[Unhandled page code] Received mode page code 8 with total length %d\n ", length);
for (int i = 0; i<length; i++)
{
printf("%02X ", buf[i]);
}
printf("\n");
break;
// Other page
default:
printf("Unknown Mode Select page code received: %02X\n",page);
break;
}
// Advance to the next page
size = buf[1] + 2;
length -= size;
buf += size;
}
}
// Do not generate an error for the time being (MINIX)
disk.code = DISK_NOERROR;
return TRUE;
}

View File

@@ -0,0 +1,44 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI hard disk ]
//
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include "disk.h"
#include "filepath.h"
//===========================================================================
//
// SCSI Hard Disk
//
//===========================================================================
class SCSIHD : public Disk
{
public:
// Basic Functions
SCSIHD();
// Constructor
void FASTCALL Reset();
// Reset
BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE);
// Open
// commands
int FASTCALL Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
BOOL FASTCALL ModeSelect(const DWORD *cdb, const BYTE *buf, int length);
// MODE SELECT(6) command
};

View File

@@ -0,0 +1,93 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Hard Disk for Apple Macintosh ]
//
//---------------------------------------------------------------------------
#include "scsihd_apple.h"
//===========================================================================
//
// SCSI hard disk (Macintosh Apple genuine)
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIHD_APPLE::SCSIHD_APPLE() : SCSIHD()
{
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD_APPLE::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
int size;
char vendor[32];
char product[32];
// Call the base class
size = SCSIHD::Inquiry(cdb, buf, major, minor);
// End if there is an error in the base class
if (size == 0) {
return 0;
}
// Vendor name
sprintf(vendor, " SEAGATE");
memcpy(&buf[8], vendor, strlen(vendor));
// Product name
sprintf(product, " ST225N");
memcpy(&buf[16], product, strlen(product));
return size;
}
//---------------------------------------------------------------------------
//
// Add Vendor special page
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD_APPLE::AddVendor(int page, BOOL change, BYTE *buf)
{
ASSERT(this);
ASSERT(buf);
// Page code 48
if ((page != 0x30) && (page != 0x3f)) {
return 0;
}
// Set the message length
buf[0] = 0x30;
buf[1] = 0x1c;
// No changeable area
if (change) {
return 30;
}
// APPLE COMPUTER, INC.
memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20);
return 30;
}

View File

@@ -0,0 +1,39 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Hard Disk for Apple Macintosh ]
//
//---------------------------------------------------------------------------
#pragma once
#include "scsihd.h"
//===========================================================================
//
// SCSI Hard Disk(Genuine Apple Macintosh)
//
//===========================================================================
class SCSIHD_APPLE : public SCSIHD
{
public:
// Basic Functions
SCSIHD_APPLE();
// Constructor
// commands
int FASTCALL Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
// Internal processing
int FASTCALL AddVendor(int page, BOOL change, BYTE *buf);
// Add vendor special page
};

View File

@@ -0,0 +1,295 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI NEC "Genuine" Hard Disk]
//
//---------------------------------------------------------------------------
#include "scsihd_nec.h"
#include "fileio.h"
//===========================================================================
//
// SCSI hard disk (PC-9801-55 NEC genuine /Anex86/T98Next)
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIHD_NEC::SCSIHD_NEC() : SCSIHD()
{
// ワーク初期化
cylinders = 0;
heads = 0;
sectors = 0;
sectorsize = 0;
imgoffset = 0;
imgsize = 0;
}
//---------------------------------------------------------------------------
//
// リトルエンディアンと想定したワードを取り出す
//
//---------------------------------------------------------------------------
static inline WORD getWordLE(const BYTE *b)
{
return ((WORD)(b[1]) << 8) | b[0];
}
//---------------------------------------------------------------------------
//
// リトルエンディアンと想定したロングワードを取り出す
//
//---------------------------------------------------------------------------
static inline DWORD getDwordLE(const BYTE *b)
{
return ((DWORD)(b[3]) << 24) | ((DWORD)(b[2]) << 16) |
((DWORD)(b[1]) << 8) | b[0];
}
//---------------------------------------------------------------------------
//
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
{
Fileio fio;
off64_t size;
BYTE hdr[512];
LPCTSTR ext;
ASSERT(this);
ASSERT(!disk.ready);
// Open as read-only
if (!fio.Open(path, Fileio::ReadOnly)) {
return FALSE;
}
// Get file size
size = fio.GetFileSize();
// ヘッダー読み込み
if (size >= (off64_t)sizeof(hdr)) {
if (!fio.Read(hdr, sizeof(hdr))) {
fio.Close();
return FALSE;
}
}
fio.Close();
// 512バイト単位であること
if (size & 0x1ff) {
return FALSE;
}
// 10MB以上
if (size < 0x9f5400) {
return FALSE;
}
// xm6iに準じて2TB
// よく似たものが wxw/wxw_cfg.cpp にもある
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
return FALSE;
}
// 拡張子別にパラメータを決定
ext = path.GetFileExt();
if (xstrcasecmp(ext, _T(".HDN")) == 0) {
// デフォルト設定としてセクタサイズ512,セクタ数25,ヘッド数8を想定
imgoffset = 0;
imgsize = size;
sectorsize = 512;
sectors = 25;
heads = 8;
cylinders = (int)(size >> 9);
cylinders >>= 3;
cylinders /= 25;
} else if (xstrcasecmp(ext, _T(".HDI")) == 0) { // Anex86 HD image?
imgoffset = getDwordLE(&hdr[4 + 4]);
imgsize = getDwordLE(&hdr[4 + 4 + 4]);
sectorsize = getDwordLE(&hdr[4 + 4 + 4 + 4]);
sectors = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4]);
heads = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4]);
cylinders = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4 + 4]);
} else if (xstrcasecmp(ext, _T(".NHD")) == 0 &&
memcmp(hdr, "T98HDDIMAGE.R0\0", 15) == 0) { // T98Next HD image?
imgoffset = getDwordLE(&hdr[0x10 + 0x100]);
cylinders = getDwordLE(&hdr[0x10 + 0x100 + 4]);
heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]);
sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]);
sectorsize = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2 + 2]);
imgsize = (off64_t)cylinders * heads * sectors * sectorsize;
}
// セクタサイズは256または512をサポート
if (sectorsize != 256 && sectorsize != 512) {
return FALSE;
}
// イメージサイズの整合性チェック
if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) {
return FALSE;
}
// セクタサイズ
for(disk.size = 16; disk.size > 0; --(disk.size)) {
if ((1 << disk.size) == sectorsize)
break;
}
if (disk.size <= 0 || disk.size > 16) {
return FALSE;
}
// ブロック数
disk.blocks = (DWORD)(imgsize >> disk.size);
disk.imgoffset = imgoffset;
// Call the base class
return Disk::Open(path);
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD_NEC::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
int size;
// 基底クラス
size = SCSIHD::Inquiry(cdb, buf, major, minor);
// 基底クラスでエラーなら終了
if (size == 0) {
return 0;
}
// SCSI1相当に変更
buf[2] = 0x01;
buf[3] = 0x01;
// Replace Vendor name
buf[8] = 'N';
buf[9] = 'E';
buf[10] = 'C';
return size;
}
//---------------------------------------------------------------------------
//
// エラーページ追加
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
{
ASSERT(this);
ASSERT(buf);
// Set the message length
buf[0] = 0x01;
buf[1] = 0x06;
// No changeable area
if (change) {
return 8;
}
// リトライカウントは0、リミットタイムは装置内部のデフォルト値を使用
return 8;
}
//---------------------------------------------------------------------------
//
// フォーマットページ追加
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
{
int size;
ASSERT(this);
ASSERT(buf);
// Set the message length
buf[0] = 0x80 | 0x03;
buf[1] = 0x16;
// 物理セクタのバイト数は変更可能に見せる(実際には変更できないが)
if (change) {
buf[0xc] = 0xff;
buf[0xd] = 0xff;
return 24;
}
if (disk.ready) {
// 1ゾーンのトラック数を設定(PC-9801-55はこの値を見ているようだ)
buf[0x2] = (BYTE)(heads >> 8);
buf[0x3] = (BYTE)heads;
// 1トラックのセクタ数を設定
buf[0xa] = (BYTE)(sectors >> 8);
buf[0xb] = (BYTE)sectors;
// 物理セクタのバイト数を設定
size = 1 << disk.size;
buf[0xc] = (BYTE)(size >> 8);
buf[0xd] = (BYTE)size;
}
// リムーバブル属性を設定(昔の名残)
if (disk.removable) {
buf[20] = 0x20;
}
return 24;
}
//---------------------------------------------------------------------------
//
// ドライブページ追加
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf)
{
ASSERT(this);
ASSERT(buf);
// Set the message length
buf[0] = 0x04;
buf[1] = 0x12;
// No changeable area
if (change) {
return 20;
}
if (disk.ready) {
// シリンダ数を設定
buf[0x2] = (BYTE)(cylinders >> 16);
buf[0x3] = (BYTE)(cylinders >> 8);
buf[0x4] = (BYTE)cylinders;
// ヘッド数を設定
buf[0x5] = (BYTE)heads;
}
return 20;
}

View File

@@ -0,0 +1,61 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI NEC "Genuine" Hard Disk]
//
//---------------------------------------------------------------------------
#pragma once
#include "scsihd.h"
//===========================================================================
//
// SCSI hard disk (PC-9801-55 NEC genuine /Anex86/T98Next)
//
//===========================================================================
class SCSIHD_NEC : public SCSIHD
{
public:
// Basic Functions
SCSIHD_NEC();
// Constructor
BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE);
// Open
// commands
int FASTCALL Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
// Internal processing
int FASTCALL AddError(BOOL change, BYTE *buf);
// Add error
int FASTCALL AddFormat(BOOL change, BYTE *buf);
// Add format
int FASTCALL AddDrive(BOOL change, BYTE *buf);
// Add drive
private:
int cylinders;
// Number of cylinders
int heads;
// Number of heads
int sectors;
// Number of sectors
int sectorsize;
// Sector size
off64_t imgoffset;
// Image offset
off64_t imgsize;
// Image size
};

View File

@@ -0,0 +1,421 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Magneto-Optical Disk]
//
//---------------------------------------------------------------------------
#include "scsimo.h"
#include "xm6.h"
#include "fileio.h"
//===========================================================================
//
// SCSI magneto-optical disk
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIMO::SCSIMO() : Disk()
{
// SCSI magneto-optical disk
disk.id = MAKEID('S', 'C', 'M', 'O');
// Set as removable
disk.removable = TRUE;
}
//---------------------------------------------------------------------------
//
// Open
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIMO::Open(const Filepath& path, BOOL attn)
{
Fileio fio;
off64_t size;
ASSERT(this);
ASSERT(!disk.ready);
// Open as read-only
if (!fio.Open(path, Fileio::ReadOnly)) {
return FALSE;
}
// Get file size
size = fio.GetFileSize();
fio.Close();
switch (size) {
// 128MB
case 0x797f400:
disk.size = 9;
disk.blocks = 248826;
break;
// 230MB
case 0xd9eea00:
disk.size = 9;
disk.blocks = 446325;
break;
// 540MB
case 0x1fc8b800:
disk.size = 9;
disk.blocks = 1041500;
break;
// 640MB
case 0x25e28000:
disk.size = 11;
disk.blocks = 310352;
break;
// Other (this is an error)
default:
return FALSE;
}
// Call the base class
Disk::Open(path);
// Attention if ready
if (disk.ready && attn) {
disk.attn = TRUE;
}
return TRUE;
}
#ifndef RASCSI
//---------------------------------------------------------------------------
//
// Load
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIMO::Load(Fileio *fio, int ver)
{
DWORD sz;
disk_t buf;
DWORD padding;
Filepath path;
ASSERT(this);
ASSERT(fio);
ASSERT(ver >= 0x0200);
// Prior to version 2.03, the disk was not saved
if (ver <= 0x0202) {
return TRUE;
}
// load size, match
if (!fio->Read(&sz, sizeof(sz))) {
return FALSE;
}
if (sz != 52) {
return FALSE;
}
// load into buffer
PROP_IMPORT(fio, buf.id);
PROP_IMPORT(fio, buf.ready);
PROP_IMPORT(fio, buf.writep);
PROP_IMPORT(fio, buf.readonly);
PROP_IMPORT(fio, buf.removable);
PROP_IMPORT(fio, buf.lock);
PROP_IMPORT(fio, buf.attn);
PROP_IMPORT(fio, buf.reset);
PROP_IMPORT(fio, buf.size);
PROP_IMPORT(fio, buf.blocks);
PROP_IMPORT(fio, buf.lun);
PROP_IMPORT(fio, buf.code);
PROP_IMPORT(fio, padding);
// Load path
if (!path.Load(fio, ver)) {
return FALSE;
}
// Always eject
Eject(TRUE);
// Move only if IDs match
if (disk.id != buf.id) {
// Not MO at the time of save. Maintain eject status
return TRUE;
}
// Re-try opening
if (!Open(path, FALSE)) {
// Cannot reopen. Maintain eject status
return TRUE;
}
// Disk cache is created in Open. Move property only
if (!disk.readonly) {
disk.writep = buf.writep;
}
disk.lock = buf.lock;
disk.attn = buf.attn;
disk.reset = buf.reset;
disk.lun = buf.lun;
disk.code = buf.code;
// loaded successfully
return TRUE;
}
#endif // RASCSI
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIMO::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
int size;
char rev[32];
ASSERT(this);
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
return FALSE;
}
// 基本データ
// buf[0] ... Optical Memory Device
// buf[1] ... 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[0] = 0x07;
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
buf[0] = 0x7f;
}
buf[1] = 0x80;
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 36 - 5; // required
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Vendor name
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
// Product name
memcpy(&buf[16], "M2513A", 6);
// Revision (XM6 version number)
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
// Size return data
size = (buf[4] + 5);
// Limit the size if the buffer is too small
if (size > (int)cdb[4]) {
size = (int)cdb[4];
}
// Success
disk.code = DISK_NOERROR;
return size;
}
//---------------------------------------------------------------------------
//
// MODE SELECT
// *Not affected by disk.code
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
int page;
int size;
ASSERT(this);
ASSERT(buf);
ASSERT(length >= 0);
// PF
if (cdb[1] & 0x10) {
// Mode Parameter header
if (length >= 12) {
// Check the block length (in bytes)
size = 1 << disk.size;
if (buf[9] != (BYTE)(size >> 16) ||
buf[10] != (BYTE)(size >> 8) || buf[11] != (BYTE)size) {
// Currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
}
buf += 12;
length -= 12;
}
// Parsing the page
while (length > 0) {
// Get the page
page = buf[0];
switch (page) {
// format device
case 0x03:
// Check the number of bytes in the physical sector
size = 1 << disk.size;
if (buf[0xc] != (BYTE)(size >> 8) ||
buf[0xd] != (BYTE)size) {
// Currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
}
break;
// vendor unique format
case 0x20:
// just ignore, for now
break;
// Other page
default:
break;
}
// Advance to the next page
size = buf[1] + 2;
length -= size;
buf += size;
}
}
// Do not generate an error for the time being (MINIX)
disk.code = DISK_NOERROR;
return TRUE;
}
//---------------------------------------------------------------------------
//
// Vendor Unique Format Page 20h (MO)
//
//---------------------------------------------------------------------------
int FASTCALL SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
{
ASSERT(this);
ASSERT(buf);
// Page code 20h
if ((page != 0x20) && (page != 0x3f)) {
return 0;
}
// Set the message length
buf[0] = 0x20;
buf[1] = 0x0a;
// No changeable area
if (change) {
return 12;
}
/*
mode page code 20h - Vendor Unique Format Page
format mode XXh type 0
information: http://h20628.www2.hp.com/km-ext/kmcsdirect/emr_na-lpg28560-1.pdf
offset description
02h format mode
03h type of format (0)
04~07h size of user band (total sectors?)
08~09h size of spare band (spare sectors?)
0A~0Bh number of bands
actual value of each 3.5inches optical medium (grabbed by Fujitsu M2513EL)
128M 230M 540M 640M
---------------------------------------------------
size of user band 3CBFAh 6CF75h FE45Ch 4BC50h
size of spare band 0400h 0401h 08CAh 08C4h
number of bands 0001h 000Ah 0012h 000Bh
further information: http://r2089.blog36.fc2.com/blog-entry-177.html
*/
if (disk.ready) {
unsigned spare = 0;
unsigned bands = 0;
if (disk.size == 9) switch (disk.blocks) {
// 128MB
case 248826:
spare = 1024;
bands = 1;
break;
// 230MB
case 446325:
spare = 1025;
bands = 10;
break;
// 540MB
case 1041500:
spare = 2250;
bands = 18;
break;
}
if (disk.size == 11) switch (disk.blocks) {
// 640MB
case 310352:
spare = 2244;
bands = 11;
break;
// 1.3GB (lpproj: not tested with real device)
case 605846:
spare = 4437;
bands = 18;
break;
}
buf[2] = 0; // format mode
buf[3] = 0; // type of format
buf[4] = (BYTE)(disk.blocks >> 24);
buf[5] = (BYTE)(disk.blocks >> 16);
buf[6] = (BYTE)(disk.blocks >> 8);
buf[7] = (BYTE)disk.blocks;
buf[8] = (BYTE)(spare >> 8);
buf[9] = (BYTE)spare;
buf[10] = (BYTE)(bands >> 8);
buf[11] = (BYTE)bands;
}
return 12;
}

View File

@@ -0,0 +1,49 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Magneto-Optical Disk]
//
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include "disk.h"
#include "filepath.h"
//===========================================================================
//
// SCSI magneto-optical disk
//
//===========================================================================
class SCSIMO : public Disk
{
public:
// Basic Functions
SCSIMO();
// Constructor
BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE);
// Open
#ifndef RASCSI
BOOL FASTCALL Load(Fileio *fio, int ver);
// Load
#endif // RASCSI
// commands
int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);
// INQUIRY command
BOOL FASTCALL ModeSelect(const DWORD *cdb, const BYTE *buf, int length);
// MODE SELECT(6) command
// Internal processing
int FASTCALL AddVendor(int page, BOOL change, BYTE *buf);
// Add vendor special page
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,8 @@
#if !defined(fileio_h)
#define fileio_h
#include "filepath.h"
#ifdef BAREMETAL
#include "ff.h"
#endif // BAREMETAL

View File

@@ -11,6 +11,8 @@
#if !defined(filepath_h)
#define filepath_h
class Fileio;
//---------------------------------------------------------------------------
//
// 定数定義

BIN
src/raspberrypi/foo.hda Normal file

Binary file not shown.

View File

@@ -144,6 +144,10 @@ GPIOBUS::~GPIOBUS()
//---------------------------------------------------------------------------
BOOL FASTCALL GPIOBUS::Init(mode_e mode)
{
#if defined(__x86_64__) || defined(__X86__)
// When we're running on x86, there is no hardware to talk to, so just return.
return true;
#else
void *map;
int i;
int j;
@@ -379,6 +383,8 @@ BOOL FASTCALL GPIOBUS::Init(mode_e mode)
SetControl(PIN_ENB, ENB_ON);
return TRUE;
#endif // ifdef __x86_64__ || __X86__
}
//---------------------------------------------------------------------------
@@ -388,6 +394,9 @@ BOOL FASTCALL GPIOBUS::Init(mode_e mode)
//---------------------------------------------------------------------------
void FASTCALL GPIOBUS::Cleanup()
{
#if defined(__x86_64__) || defined(__X86__)
return;
#else
int i;
int pin;
@@ -419,6 +428,7 @@ void FASTCALL GPIOBUS::Cleanup()
// Set drive strength back to 8mA
DrvConfig(3);
#endif // ifdef __x86_64__ || __X86__
}
//---------------------------------------------------------------------------
@@ -428,6 +438,9 @@ void FASTCALL GPIOBUS::Cleanup()
//---------------------------------------------------------------------------
void FASTCALL GPIOBUS::Reset()
{
#if defined(__x86_64__) || defined(__X86__)
return;
#else
int i;
int j;
@@ -506,6 +519,7 @@ void FASTCALL GPIOBUS::Reset()
// Initialize all signals
signals = 0;
#endif // ifdef __x86_64__ || __X86__
}
//---------------------------------------------------------------------------
@@ -515,6 +529,9 @@ void FASTCALL GPIOBUS::Reset()
//---------------------------------------------------------------------------
DWORD FASTCALL GPIOBUS::Aquire()
{
#if defined(__x86_64__) || defined(__X86__)
return 0;
#else
signals = *level;
#if SIGNAL_CONTROL_MODE < 2
@@ -523,6 +540,7 @@ DWORD FASTCALL GPIOBUS::Aquire()
#endif // SIGNAL_CONTROL_MODE
return signals;
#endif // ifdef __x86_64__ || __X86__
}
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,2 @@
if $programname == 'RASCSI' then /var/log/rascsi.log
& stop

View File

@@ -0,0 +1,19 @@
[Unit]
Description=RaSCSI service
After=network.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/rascsi
# Example: If you want to automatically attach a hard disk at startup, change
# the ExecStart line to:
# ExecStart=/usr/local/bin/rascsi -ID1 /home/pi/images/harddisk.hda
ExecStop=/usr/local/bin/rasctl -stop
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=RASCSI
[Install]
WantedBy=multi-user.target

14
src/raspberrypi/rascsi.1 Normal file
View File

@@ -0,0 +1,14 @@
.TH rascsi 1
.SH NAME
rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins
.SH SYNOPSIS
.B rascsi
[\fB\-HDn\fR \fIfile\fR] ...
.SH DESCRIPTION
.B corrupt
modifies files by toggling a randomly chosen bit.
.SH OPTIONS
.TP
.BR \-n ", " \-\-bits =\fIBITS\fR
Set the number of bits to modify.
Default is one bit.

View File

@@ -13,10 +13,20 @@
#include "xm6.h"
#include "filepath.h"
#include "fileio.h"
#include "disk.h"
#include "devices/disk.h"
#include "devices/sasihd.h"
#include "devices/scsihd.h"
#include "devices/scsihd_apple.h"
#include "devices/scsihd_nec.h"
#include "devices/scsicd.h"
#include "devices/scsimo.h"
#include "devices/scsi_host_bridge.h"
#include "controllers/scsidev_ctrl.h"
#include "controllers/sasidev_ctrl.h"
#include "gpiobus.h"
#include "spdlog/spdlog.h"
//---------------------------------------------------------------------------
//
// Constant declarations
@@ -607,20 +617,24 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
return TRUE;
}
bool has_suffix(const char* string, const char* suffix) {
int string_len = strlen(string);
int suffix_len = strlen(suffix);
return (string_len >= suffix_len)
&& (xstrcasecmp(string + (string_len - suffix_len), suffix) == 0);
}
//---------------------------------------------------------------------------
//
// Argument Parsing
//
//---------------------------------------------------------------------------
BOOL ParseArgument(int argc, char* argv[])
{
#ifdef BAREMETAL
BOOL ParseConfig(int argc, char* argv[])
{
FRESULT fr;
FIL fp;
char line[512];
#else
int i;
#endif // BAREMETAL
int id;
int un;
int type;
@@ -629,7 +643,6 @@ BOOL ParseArgument(int argc, char* argv[])
int len;
char *ext;
#ifdef BAREMETAL
// Mount the SD card
fr = f_mount(&fatfs, "", 1);
if (fr != FR_OK) {
@@ -642,19 +655,10 @@ BOOL ParseArgument(int argc, char* argv[])
if (fr != FR_OK) {
return FALSE;
}
#else
// If the ID and path are not specified, the processing is interrupted
if (argc < 3) {
return TRUE;
}
i = 1;
argc--;
#endif // BAREMETAL
// Start Decoding
while (TRUE) {
#ifdef BAREMETAL
// Get one Line
memset(line, 0x00, sizeof(line));
if (f_gets(line, sizeof(line) -1, &fp) == NULL) {
@@ -670,16 +674,8 @@ BOOL ParseArgument(int argc, char* argv[])
line[len - 1] = '\0';
len--;
}
#else
if (argc < 2) {
break;
}
argc -= 2;
#endif // BAREMETAL
// Get the ID and Path
#ifdef BAREMETAL
argID = &line[0];
argPath = &line[4];
line[3] = '\0';
@@ -688,18 +684,6 @@ BOOL ParseArgument(int argc, char* argv[])
if (argID[0] == '\0' || argPath[0] == '\0') {
continue;
}
#else
argID = argv[i++];
argPath = argv[i++];
// Check if the argument is invalid
if (argID[0] != '-') {
FPRT(stderr,
"Error : Invalid argument(-IDn or -HDn) [%s]\n", argID);
goto parse_error;
}
argID++;
#endif // BAREMETAL
if (strlen(argID) == 3 && xstrncasecmp(argID, "id", 2) == 0) {
// ID or ID Format
@@ -739,9 +723,7 @@ BOOL ParseArgument(int argc, char* argv[])
// The ID unit is good - create the id and unit number
id = ((argID[3] - '0') + 10) / UnitNum;
un = ((argID[3] - '0') + 10) % UnitNum;
#ifdef BAREMETAL
argPath++;
#endif // BAREMETAL
} else {
FPRT(stderr,
"Error : Invalid argument(IDn or HDn) [%s]\n", argID);
@@ -811,10 +793,8 @@ BOOL ParseArgument(int argc, char* argv[])
}
}
#ifdef BAREMETAL
// Close the configuration file
f_close(&fp);
#endif // BAREMETAL
// Display the device list
ListDevice(stdout);
@@ -823,13 +803,102 @@ BOOL ParseArgument(int argc, char* argv[])
parse_error:
#ifdef BAREMETAL
// Close the configuration file
f_close(&fp);
#endif // BAREMETAL
return FALSE;
}
#else
bool ParseArgument(int argc, char* argv[])
{
int id = -1;
bool is_sasi = false;
int max_id = 7;
int opt;
while ((opt = getopt(argc, argv, "-IiHhD:d:")) != -1) {
switch (opt) {
case 'I':
case 'i':
is_sasi = false;
max_id = 7;
id = -1;
continue;
case 'H':
case 'h':
is_sasi = true;
max_id = 15;
id = -1;
continue;
case 'D':
case 'd': {
char* end;
id = strtol(optarg, &end, 10);
if (*end || (id < 0) || (max_id < id)) {
fprintf(stderr, "%s: invalid %s (0-%d)\n",
optarg, is_sasi ? "HD" : "ID", max_id);
return false;
}
continue;
}
default:
return false;
case 1:
break;
}
if (id < 0) {
fprintf(stderr, "%s: ID not specified\n", optarg);
return false;
} else if (disk[id] && !disk[id]->IsNULL()) {
fprintf(stderr, "%d: duplicate ID\n", id);
return false;
}
char* path = optarg;
int type = -1;
if (has_suffix(path, ".hdf")
|| has_suffix(path, ".hds")
|| has_suffix(path, ".hdn")
|| has_suffix(path, ".hdi")
|| has_suffix(path, ".hda")
|| has_suffix(path, ".nhd")) {
type = 0;
} else if (has_suffix(path, ".mos")) {
type = 2;
} else if (has_suffix(path, ".iso")) {
type = 3;
} else if (xstrcasecmp(path, "bridge") == 0) {
type = 4;
} else {
// Cannot determine the file type
fprintf(stderr,
"%s: unknown file extension\n", path);
return false;
}
int un = 0;
if (is_sasi) {
un = id % UnitNum;
id /= UnitNum;
}
// Execute the command
if (!ProcessCmd(stderr, id, un, 0, type, path)) {
return false;
}
id = -1;
}
// Display the device list
ListDevice(stdout);
return true;
}
#endif // BAREMETAL
#ifndef BAREMETAL
//---------------------------------------------------------------------------
@@ -1014,13 +1083,19 @@ int main(int argc, char* argv[])
#ifdef BAREMETAL
// BUSY assert (to hold the host side)
bus->SetBSY(TRUE);
#endif
// Argument parsing
if (!ParseConfig(argc, argv)) {
ret = EINVAL;
goto err_exit;
}
#else
// Argument parsing
if (!ParseArgument(argc, argv)) {
ret = EINVAL;
goto err_exit;
}
#endif
#ifdef BAREMETAL
// Release the busy signal

14
src/raspberrypi/rasctl.1 Normal file
View File

@@ -0,0 +1,14 @@
.TH rascsi 1
.SH NAME
rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins
.SH SYNOPSIS
.B rascsi
[\fB\-HDn\fR \fIfile\fR] ...
.SH DESCRIPTION
.B corrupt
modifies files by toggling a randomly chosen bit.
.SH OPTIONS
.TP
.BR \-n ", " \-\-bits =\fIBITS\fR
Set the number of bits to modify.
Default is one bit.

View File

@@ -39,7 +39,7 @@ BOOL SendCommand(char *buf)
// Send the command
fp = fdopen(fd, "r+");
setvbuf(fp, NULL, _IONBF, 0);
fprintf(fp, buf);
fputs(buf, fp);
// Receive the message
while (1) {