mirror of
https://github.com/thewesker/RASCSI.git
synced 2025-12-20 12:21:10 -05:00
#16 Lots more refactoring.... doesn't work anymore... work in progress
This commit is contained in:
27
src/raspberrypi/.vscode/launch.json
vendored
Normal file
27
src/raspberrypi/.vscode/launch.json
vendored
Normal 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
14
src/raspberrypi/.vscode/settings.json
vendored
Normal 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
19
src/raspberrypi/.vscode/tasks.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -50,12 +50,17 @@ SRC_RASCSI = \
|
||||
scsi.cpp \
|
||||
gpiobus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp
|
||||
fileio.cpp\
|
||||
rascsi_mgr.cpp\
|
||||
command_thread.cpp\
|
||||
os.cpp\
|
||||
rasctl_command.cpp
|
||||
SRC_RASCSI += $(notdir $(shell find ./controllers -name '*.cpp'))
|
||||
SRC_RASCSI += $(notdir $(shell find ./disks -name '*.cpp'))
|
||||
|
||||
SRC_RASCTL = \
|
||||
rasctl.cpp
|
||||
rasctl.cpp\
|
||||
rasctl_command.cpp
|
||||
|
||||
SRC_RASDUMP = \
|
||||
rasdump.cpp \
|
||||
@@ -107,9 +112,11 @@ ALL: all
|
||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt
|
||||
|
||||
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) $(BINDIR)
|
||||
@echo -- Linking $(RASCSI)
|
||||
$(CXX) -o $@ $(OBJ_RASCSI) -lpthread
|
||||
|
||||
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) $(BINDIR)
|
||||
@echo -- Linking $(RASCTL)
|
||||
$(CXX) -o $@ $(OBJ_RASCTL)
|
||||
|
||||
$(RASDUMP): $(OBJ_RASDUMP) $(BINDIR)
|
||||
|
||||
689
src/raspberrypi/command_thread.cpp
Normal file
689
src/raspberrypi/command_thread.cpp
Normal file
@@ -0,0 +1,689 @@
|
||||
#include "os.h"
|
||||
|
||||
#include "rasctl_command.h"
|
||||
#include "command_thread.h"
|
||||
#include "rascsi_mgr.h"
|
||||
#include "sasihd.h"
|
||||
#include "scsihd.h"
|
||||
#include "scsihd_nec.h"
|
||||
#include "scsihd_apple.h"
|
||||
#include "scsicd.h"
|
||||
#include "scsimo.h"
|
||||
#include "scsi_host_bridge.h"
|
||||
|
||||
BOOL Command_Thread::m_running = FALSE;
|
||||
int Command_Thread::m_monsocket = -1; // Monitor Socket
|
||||
pthread_t Command_Thread::m_monthread; // Monitor Thread
|
||||
|
||||
|
||||
void Command_Thread::Start(){
|
||||
m_running = TRUE;
|
||||
}
|
||||
void Command_Thread::Stop(){
|
||||
m_running = FALSE;
|
||||
}
|
||||
|
||||
BOOL Command_Thread::IsRunning(){
|
||||
return m_running;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Command_Thread::Init()
|
||||
{
|
||||
|
||||
#ifndef BAREMETAL
|
||||
struct sockaddr_in server;
|
||||
int yes;
|
||||
|
||||
// Create socket for monitor
|
||||
m_monsocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
memset(&server, 0, sizeof(server));
|
||||
server.sin_family = PF_INET;
|
||||
server.sin_port = htons(6868);
|
||||
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
// allow address reuse
|
||||
yes = 1;
|
||||
if (setsockopt(
|
||||
m_monsocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0){
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Bind
|
||||
if (bind(m_monsocket, (struct sockaddr *)&server,
|
||||
sizeof(struct sockaddr_in)) < 0) {
|
||||
FPRT(stderr, "Error : Already running?\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Create Monitor Thread
|
||||
pthread_create(&m_monthread, NULL, MonThread, NULL);
|
||||
|
||||
|
||||
#endif // BAREMETAL
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void Command_Thread::Close(){
|
||||
// Close the monitor socket
|
||||
if (m_monsocket >= 0) {
|
||||
close(m_monsocket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Argument Parsing
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef BAREMETAL
|
||||
BOOL ParseConfig(int argc, char* argv[])
|
||||
{
|
||||
FRESULT fr;
|
||||
FIL fp;
|
||||
char line[512];
|
||||
int id;
|
||||
int un;
|
||||
int type;
|
||||
char *argID;
|
||||
char *argPath;
|
||||
int len;
|
||||
char *ext;
|
||||
|
||||
// Mount the SD card
|
||||
fr = f_mount(&fatfs, "", 1);
|
||||
if (fr != FR_OK) {
|
||||
FPRT(stderr, "Error : SD card mount failed.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If there is no setting file, the processing is interrupted
|
||||
fr = f_open(&fp, "rascsi.ini", FA_READ);
|
||||
if (fr != FR_OK) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Start Decoding
|
||||
|
||||
while (TRUE) {
|
||||
// Get one Line
|
||||
memset(line, 0x00, sizeof(line));
|
||||
if (f_gets(line, sizeof(line) -1, &fp) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Delete the CR/LF
|
||||
len = strlen(line);
|
||||
while (len > 0) {
|
||||
if (line[len - 1] != '\r' && line[len - 1] != '\n') {
|
||||
break;
|
||||
}
|
||||
line[len - 1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
// Get the ID and Path
|
||||
argID = &line[0];
|
||||
argPath = &line[4];
|
||||
line[3] = '\0';
|
||||
|
||||
// Check if the line is an empty string
|
||||
if (argID[0] == '\0' || argPath[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen(argID) == 3 && xstrncasecmp(argID, "id", 2) == 0) {
|
||||
// ID or ID Format
|
||||
|
||||
// Check that the ID number is valid (0-7)
|
||||
if (argID[2] < '0' || argID[2] > '7') {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(IDn n=0-7) [%c]\n", argID[2]);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
// The ID unit is good
|
||||
id = argID[2] - '0';
|
||||
un = 0;
|
||||
} else if (xstrncasecmp(argID, "hd", 2) == 0) {
|
||||
// HD or HD format
|
||||
|
||||
if (strlen(argID) == 3) {
|
||||
// Check that the HD number is valid (0-9)
|
||||
if (argID[2] < '0' || argID[2] > '9') {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(HDn n=0-15) [%c]\n", argID[2]);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
// ID was confirmed
|
||||
id = (argID[2] - '0') / UnitNum;
|
||||
un = (argID[2] - '0') % UnitNum;
|
||||
} else if (strlen(argID) == 4) {
|
||||
// Check that the HD number is valid (10-15)
|
||||
if (argID[2] != '1' || argID[3] < '0' || argID[3] > '5') {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(HDn n=0-15) [%c]\n", argID[2]);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
// The ID unit is good - create the id and unit number
|
||||
id = ((argID[3] - '0') + 10) / UnitNum;
|
||||
un = ((argID[3] - '0') + 10) % UnitNum;
|
||||
argPath++;
|
||||
} else {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(IDn or HDn) [%s]\n", argID);
|
||||
goto parse_error;
|
||||
}
|
||||
} else {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(IDn or HDn) [%s]\n", argID);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
// Skip if there is already an active device
|
||||
if (disk[id * UnitNum + un] &&
|
||||
!disk[id * UnitNum + un]->IsNULL()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Initialize device type
|
||||
type = -1;
|
||||
|
||||
// Check ethernet and host bridge
|
||||
if (xstrcasecmp(argPath, "bridge") == 0) {
|
||||
type = 4;
|
||||
} else {
|
||||
// Check the path length
|
||||
len = strlen(argPath);
|
||||
if (len < 5) {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(File path is short) [%s]\n",
|
||||
argPath);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
// Does the file have an extension?
|
||||
if (argPath[len - 4] != '.') {
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(No extension) [%s]\n", argPath);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
// Figure out what the type is
|
||||
ext = &argPath[len - 3];
|
||||
if (xstrcasecmp(ext, "hdf") == 0 ||
|
||||
xstrcasecmp(ext, "hds") == 0 ||
|
||||
xstrcasecmp(ext, "hdn") == 0 ||
|
||||
xstrcasecmp(ext, "hdi") == 0 || xstrcasecmp(ext, "nhd") == 0 ||
|
||||
xstrcasecmp(ext, "hda") == 0) {
|
||||
// HD(SASI/SCSI)
|
||||
type = 0;
|
||||
} else if (strcasecmp(ext, "mos") == 0) {
|
||||
// MO
|
||||
type = 2;
|
||||
} else if (strcasecmp(ext, "iso") == 0) {
|
||||
// CD
|
||||
type = 3;
|
||||
} else {
|
||||
// Cannot determine the file type
|
||||
FPRT(stderr,
|
||||
"Error : Invalid argument(file type) [%s]\n", ext);
|
||||
goto parse_error;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the command
|
||||
if (!ExecuteCommand(stderr, id, un, 0, type, argPath)) {
|
||||
goto parse_error;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the configuration file
|
||||
f_close(&fp);
|
||||
|
||||
// Display the device list
|
||||
ListDevice(stdout);
|
||||
|
||||
return TRUE;
|
||||
|
||||
parse_error:
|
||||
|
||||
// Close the configuration file
|
||||
f_close(&fp);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
#endif // BAREMETAL
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Monitor Thread
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void *Command_Thread::MonThread(void *param)
|
||||
{
|
||||
#ifndef BAREMETAL
|
||||
struct sched_param schedparam;
|
||||
struct sockaddr_in client;
|
||||
socklen_t len;
|
||||
int fd;
|
||||
FILE *fp;
|
||||
char buf[BUFSIZ];
|
||||
char *p;
|
||||
Rasctl_Command *new_command;
|
||||
|
||||
|
||||
// Scheduler Settings
|
||||
schedparam.sched_priority = 0;
|
||||
sched_setscheduler(0, SCHED_IDLE, &schedparam);
|
||||
|
||||
// Set the affinity to a specific processor core
|
||||
FixCpu(2);
|
||||
|
||||
// Wait for the execution to start
|
||||
while (!m_running) {
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
// Setup the monitor socket to receive commands
|
||||
listen(m_monsocket, 1);
|
||||
|
||||
while (1) {
|
||||
// Wait for connection
|
||||
memset(&client, 0, sizeof(client));
|
||||
len = sizeof(client);
|
||||
fd = accept(m_monsocket, (struct sockaddr*)&client, &len);
|
||||
if (fd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Fetch the command
|
||||
fp = fdopen(fd, "r+");
|
||||
p = fgets(buf, BUFSIZ, fp);
|
||||
|
||||
// Failed to get the command
|
||||
if (!p) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
// Remove the newline character
|
||||
p[strlen(p) - 1] = 0;
|
||||
|
||||
// List all of the devices
|
||||
if (xstrncasecmp(p, "list", 4) == 0) {
|
||||
Rascsi_Manager::GetInstance()->ListDevice(fp);
|
||||
goto next;
|
||||
}
|
||||
|
||||
new_command = Rasctl_Command::DeSerialize((BYTE*)p,BUFSIZ);
|
||||
|
||||
// // Wait until we becom idle
|
||||
// while (m_running) {
|
||||
// usleep(500 * 1000);
|
||||
// }
|
||||
|
||||
// Execute the command
|
||||
ExecuteCommand(fp, new_command);
|
||||
|
||||
next:
|
||||
// Release the connection
|
||||
fclose(fp);
|
||||
close(fd);
|
||||
}
|
||||
#endif // BAREMETAL
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL ValidateCommand(rasctl_command *cmd){
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// BOOL Command_Thread::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 ((id < 0) || (max_id < id)) {
|
||||
// fprintf(stderr, "%s: invalid %s (0-%d)\n",
|
||||
// optarg, is_sasi ? "HD" : "ID", max_id);
|
||||
// return false;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
// default:
|
||||
// return false;
|
||||
|
||||
// case 1:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (id < 0) {
|
||||
// fprintf(stderr, "%s: ID not specified\n", optarg);
|
||||
// return false;
|
||||
// } else if (Rascsi_Manager::GetInstance()->m_disk[id] && !Rascsi_Manager::GetInstance()->m_disk[id]->IsNULL()) {
|
||||
// fprintf(stderr, "%d: duplicate ID\n", id);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// char* path = optarg;
|
||||
// int type = -1;
|
||||
// if (HasSuffix(path, ".hdf")
|
||||
// || HasSuffix(path, ".hds")
|
||||
// || HasSuffix(path, ".hdn")
|
||||
// || HasSuffix(path, ".hdi")
|
||||
// || HasSuffix(path, ".hda")
|
||||
// || HasSuffix(path, ".nhd")) {
|
||||
// type = 0;
|
||||
// } else if (HasSuffix(path, ".mos")) {
|
||||
// type = 2;
|
||||
// } else if (HasSuffix(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 % Rascsi_Manager::UnitNum;
|
||||
// id /= Rascsi_Manager::UnitNum;
|
||||
// }
|
||||
|
||||
// // Execute the command
|
||||
// if (!ExecuteCommand(stderr, id, un, 0, type, path)) {
|
||||
// return false;
|
||||
// }
|
||||
// id = -1;
|
||||
// }
|
||||
|
||||
// // Display the device list
|
||||
// Rascsi_Manager::GetInstance()->ListDevice(stdout);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// if (type == 0) {
|
||||
// // Passed the check
|
||||
// if (!file) {
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // Check that command is at least 5 characters long
|
||||
// len = strlen(file);
|
||||
// if (len < 5) {
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // Check the extension
|
||||
// if (file[len - 4] != '.') {
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // If the extension is not SASI type, replace with SCSI
|
||||
// ext = &file[len - 3];
|
||||
// if (xstrcasecmp(ext, "hdf") != 0) {
|
||||
// type = 1;
|
||||
// }
|
||||
|
||||
// // Check the Controller Number
|
||||
// if (cmd->id < 0 || id >= Rascsi_Manager::GetInstance()->CtrlMax) {
|
||||
// FPRT(fp, "Error : Invalid ID\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // Check the Unit Number
|
||||
// if (cmd->un < 0 || un >= Rascsi_Manager::GetInstance()->UnitNum) {
|
||||
// FPRT(fp, "Error : Invalid unit number\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Command Processing
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Command_Thread::ExecuteCommand(FILE *fp, Rasctl_Command *incoming_command)
|
||||
{
|
||||
Filepath filepath;
|
||||
BOOL result = FALSE;
|
||||
|
||||
switch(incoming_command->cmd){
|
||||
case rasctl_cmd_shutdown:
|
||||
result = DoShutdown(fp,incoming_command);
|
||||
break;
|
||||
case rasctl_cmd_list:
|
||||
result = DoList(fp,incoming_command);
|
||||
break;
|
||||
case rasctl_cmd_attach:
|
||||
result = DoAttach(fp,incoming_command);
|
||||
break;
|
||||
case rasctl_cmd_insert:
|
||||
result = DoInsert(fp,incoming_command);
|
||||
break;
|
||||
case rasctl_cmd_eject:
|
||||
result = DoEject(fp,incoming_command);
|
||||
break;
|
||||
case rasctl_cmd_protect:
|
||||
result = DoProtect(fp,incoming_command);
|
||||
break;
|
||||
case rasctl_cmd_detach:
|
||||
result = DoDetach(fp,incoming_command);
|
||||
break;
|
||||
default:
|
||||
printf("UNKNOWN COMMAND RECEIVED\n");
|
||||
}
|
||||
|
||||
if(!result){
|
||||
fputs("Unknown server error", fp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL Command_Thread::DoShutdown(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
BOOL Command_Thread::DoList(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
BOOL Command_Thread::DoAttach(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
BOOL Command_Thread::DoDetach(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
BOOL Command_Thread::DoInsert(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
BOOL Command_Thread::DoEject(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
BOOL Command_Thread::DoProtect(FILE *fp, Rasctl_Command *incoming_command){return FALSE;}
|
||||
|
||||
|
||||
// BOOL Command_Thread::DoAttach(File *fp, Rasctl_Command *incoming_command){
|
||||
|
||||
// // Connect Command
|
||||
// if (cmd == rasctl_cmd_attach) { // ATTACH
|
||||
// // Distinguish between SASI and SCSI
|
||||
// ext = NULL;
|
||||
// pUnit = NULL;
|
||||
|
||||
// }
|
||||
|
||||
// // Create a new drive, based upon type
|
||||
// switch (type) {
|
||||
// case 0: // HDF
|
||||
// pUnit = new SASIHD();
|
||||
// break;
|
||||
// case 1: // HDS/HDN/HDI/NHD/HDA
|
||||
// if (ext == NULL) {
|
||||
// break;
|
||||
// }
|
||||
// if (xstrcasecmp(ext, "hdn") == 0 ||
|
||||
// xstrcasecmp(ext, "hdi") == 0 || xstrcasecmp(ext, "nhd") == 0) {
|
||||
// pUnit = new SCSIHD_NEC();
|
||||
// } else if (xstrcasecmp(ext, "hda") == 0) {
|
||||
// pUnit = new SCSIHD_APPLE();
|
||||
// } else {
|
||||
// pUnit = new SCSIHD();
|
||||
// }
|
||||
// break;
|
||||
// case 2: // MO
|
||||
// pUnit = new SCSIMO();
|
||||
// break;
|
||||
// case 3: // CD
|
||||
// pUnit = new SCSICD();
|
||||
// break;
|
||||
// case 4: // BRIDGE
|
||||
// pUnit = new SCSIBR();
|
||||
// break;
|
||||
// default:
|
||||
// FPRT(fp, "Error : Invalid device type\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // drive checks files
|
||||
// if (type <= 1 || (type <= 3 && xstrcasecmp(file, "-") != 0)) {
|
||||
// // Set the Path
|
||||
// filepath.SetPath(file);
|
||||
|
||||
// // Open the file path
|
||||
// if (!pUnit->Open(filepath)) {
|
||||
// FPRT(fp, "Error : File open error [%s]\n", file);
|
||||
// delete pUnit;
|
||||
// return FALSE;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Set the cache to write-through
|
||||
// pUnit->SetCacheWB(FALSE);
|
||||
|
||||
// // Replace with the newly created unit
|
||||
// map[id * Rascsi_Manager::GetInstance()->UnitNum + un] = pUnit;
|
||||
|
||||
// // Re-map the controller
|
||||
// Rascsi_Manager::GetInstance()->MapControler(fp, map);
|
||||
// return TRUE;
|
||||
// }
|
||||
|
||||
// // Is this a valid command?
|
||||
// if (cmd > 4) {
|
||||
// FPRT(fp, "Error : Invalid command\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // Does the controller exist?
|
||||
// if (Rascsi_Manager::GetInstance()->m_ctrl[id] == NULL) {
|
||||
// FPRT(fp, "Error : No such device\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // Does the unit exist?
|
||||
// pUnit = Rascsi_Manager::GetInstance()->m_disk[id * Rascsi_Manager::GetInstance()->UnitNum + un];
|
||||
// if (pUnit == NULL) {
|
||||
// FPRT(fp, "Error : No such device\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// // Disconnect Command
|
||||
// if (cmd == 1) { // DETACH
|
||||
// // Free the existing unit
|
||||
// map[id * Rascsi_Manager::GetInstance()->UnitNum + un] = NULL;
|
||||
|
||||
// // Re-map the controller
|
||||
// Rascsi_Manager::GetInstance()->MapControler(fp, map);
|
||||
// return TRUE;
|
||||
// }
|
||||
|
||||
// // Valid only for MO or CD
|
||||
// if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O') &&
|
||||
// pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) {
|
||||
// FPRT(fp, "Error : Operation denied(Deveice isn't removable)\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// switch (cmd) {
|
||||
// case 2: // INSERT
|
||||
// // Set the file path
|
||||
// filepath.SetPath(file);
|
||||
|
||||
// // Open the file
|
||||
// if (!pUnit->Open(filepath)) {
|
||||
// FPRT(fp, "Error : File open error [%s]\n", file);
|
||||
// return FALSE;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case 3: // EJECT
|
||||
// pUnit->Eject(TRUE);
|
||||
// break;
|
||||
|
||||
// case 4: // PROTECT
|
||||
// if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) {
|
||||
// FPRT(fp, "Error : Operation denied(Deveice isn't MO)\n");
|
||||
// return FALSE;
|
||||
// }
|
||||
// pUnit->WriteP(!pUnit->IsWriteP());
|
||||
// break;
|
||||
// default:
|
||||
// ASSERT(FALSE);
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
// return TRUE;
|
||||
// }
|
||||
|
||||
BOOL Command_Thread::HasSuffix(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);
|
||||
}
|
||||
|
||||
55
src/raspberrypi/command_thread.h
Normal file
55
src/raspberrypi/command_thread.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ Command thread ]
|
||||
//
|
||||
// This is a background thread that runs, listening for commands on port
|
||||
// 6868 for commands from the rasctl utility. This also includes the logic
|
||||
// for handling the initialization commands that are specified at startup.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "xm6.h"
|
||||
#include "os.h"
|
||||
#include "rasctl_command.h"
|
||||
|
||||
class Command_Thread{
|
||||
|
||||
public:
|
||||
static BOOL Init();
|
||||
static void Start();
|
||||
static void Stop();
|
||||
static BOOL IsRunning();
|
||||
static void Close();
|
||||
static void KillHandler();
|
||||
static BOOL ParseArgument(int argc, char* argv[]);
|
||||
static BOOL ParseConfig(int argc, char* argv[]);
|
||||
static BOOL ExecuteCommand(FILE *fp, Rasctl_Command *new_command);
|
||||
static void *MonThread(void *param);
|
||||
static BOOL Parse_Rasctl_Message(char *buf, Rasctl_Command *cmd);
|
||||
|
||||
private:
|
||||
static int m_monsocket; // Monitor Socket
|
||||
static pthread_t m_monthread; // Monitor Thread
|
||||
static BOOL m_running;
|
||||
|
||||
static BOOL HasSuffix(const char* string, const char* suffix);
|
||||
static BOOL DoShutdown(FILE *fp, Rasctl_Command *incoming_command);
|
||||
static BOOL DoList(FILE *fp, Rasctl_Command *incoming_command);
|
||||
static BOOL DoAttach(FILE *fp, Rasctl_Command *incoming_command);
|
||||
static BOOL DoDetach(FILE *fp, Rasctl_Command *incoming_command);
|
||||
static BOOL DoInsert(FILE *fp, Rasctl_Command *incoming_command);
|
||||
static BOOL DoEject(FILE *fp, Rasctl_Command *incoming_command);
|
||||
static BOOL DoProtect(FILE *fp, Rasctl_Command *incoming_command);
|
||||
|
||||
};
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
#if !defined(log_h)
|
||||
#define log_h
|
||||
|
||||
#ifdef BAREMETAL
|
||||
#define FPRT(fp, ...) printf( __VA_ARGS__ )
|
||||
#else
|
||||
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
||||
#endif // BAREMETAL
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ログ
|
||||
|
||||
28
src/raspberrypi/os.cpp
Normal file
28
src/raspberrypi/os.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "os.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Pin the thread to a specific CPU
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FixCpu(int cpu)
|
||||
{
|
||||
#ifndef BAREMETAL
|
||||
cpu_set_t cpuset;
|
||||
int cpus;
|
||||
|
||||
// Get the number of CPUs
|
||||
CPU_ZERO(&cpuset);
|
||||
sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
cpus = CPU_COUNT(&cpuset);
|
||||
|
||||
// Set the thread affinity
|
||||
if (cpu < cpus) {
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(cpu, &cpuset);
|
||||
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
}
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
@@ -153,4 +153,11 @@ typedef const char *LPCSTR;
|
||||
#define xstrcasecmp strcasecmp
|
||||
#define xstrncasecmp strncasecmp
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Pin the thread to a specific CPU
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FixCpu(int cpu);
|
||||
|
||||
#endif // os_h
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
406
src/raspberrypi/rascsi_mgr.cpp
Normal file
406
src/raspberrypi/rascsi_mgr.cpp
Normal file
@@ -0,0 +1,406 @@
|
||||
#include "rascsi_mgr.h"
|
||||
#include "log.h"
|
||||
#include "sasidev_ctrl.h"
|
||||
#include "scsidev_ctrl.h"
|
||||
|
||||
Rascsi_Manager *Rascsi_Manager::m_instance = (Rascsi_Manager*)nullptr;
|
||||
|
||||
|
||||
SASIDEV *Rascsi_Manager::m_ctrl[CtrlMax]; // Controller
|
||||
Disk *Rascsi_Manager::m_disk[CtrlMax * UnitNum]; // Disk
|
||||
GPIOBUS *Rascsi_Manager::m_bus;
|
||||
|
||||
int Rascsi_Manager::m_actid = -1;
|
||||
BUS::phase_t Rascsi_Manager::m_phase = BUS::busfree;
|
||||
BYTE Rascsi_Manager::m_data = 0;
|
||||
DWORD Rascsi_Manager::m_now = 0;
|
||||
BOOL Rascsi_Manager::m_active = FALSE;
|
||||
BOOL Rascsi_Manager::m_running = FALSE;
|
||||
std::timed_mutex Rascsi_Manager::m_locked;
|
||||
|
||||
Rascsi_Manager* Rascsi_Manager::GetInstance(){
|
||||
if(m_instance != nullptr){
|
||||
m_instance = new Rascsi_Manager();
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Controller Mapping
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Rascsi_Manager::MapControler(FILE *fp, Disk **map)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int unitno;
|
||||
int sasi_num;
|
||||
int scsi_num;
|
||||
|
||||
// Replace the changed unit
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
for (j = 0; j < UnitNum; j++) {
|
||||
unitno = i * UnitNum + j;
|
||||
if (m_disk[unitno] != map[unitno]) {
|
||||
// Check if the original unit exists
|
||||
if (m_disk[unitno]) {
|
||||
// Disconnect it from the controller
|
||||
if (m_ctrl[i]) {
|
||||
m_ctrl[i]->SetUnit(j, NULL);
|
||||
}
|
||||
|
||||
// Free the Unit
|
||||
delete m_disk[unitno];
|
||||
}
|
||||
|
||||
// Setup a new unit
|
||||
m_disk[unitno] = map[unitno];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reconfigure all of the controllers
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
// Examine the unit configuration
|
||||
sasi_num = 0;
|
||||
scsi_num = 0;
|
||||
for (j = 0; j < UnitNum; j++) {
|
||||
unitno = i * UnitNum + j;
|
||||
// branch by unit type
|
||||
if (m_disk[unitno]) {
|
||||
if (m_disk[unitno]->IsSASI()) {
|
||||
// Drive is SASI, so increment SASI count
|
||||
sasi_num++;
|
||||
} else {
|
||||
// Drive is SCSI, so increment SCSI count
|
||||
scsi_num++;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the unit
|
||||
if (m_ctrl[i]) {
|
||||
m_ctrl[i]->SetUnit(j, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no units connected
|
||||
if (sasi_num == 0 && scsi_num == 0) {
|
||||
if (m_ctrl[i]) {
|
||||
delete m_ctrl[i];
|
||||
m_ctrl[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Mixture of SCSI and SASI
|
||||
if (sasi_num > 0 && scsi_num > 0) {
|
||||
FPRT(fp, "Error : SASI and SCSI can't be mixed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sasi_num > 0) {
|
||||
// Only SASI Unit(s)
|
||||
|
||||
// Release the controller if it is not SASI
|
||||
if (m_ctrl[i] && !m_ctrl[i]->IsSASI()) {
|
||||
delete m_ctrl[i];
|
||||
m_ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Create a new SASI controller
|
||||
if (!m_ctrl[i]) {
|
||||
m_ctrl[i] = new SASIDEV();
|
||||
m_ctrl[i]->Connect(i, m_bus);
|
||||
}
|
||||
} else {
|
||||
// Only SCSI Unit(s)
|
||||
|
||||
// Release the controller if it is not SCSI
|
||||
if (m_ctrl[i] && !m_ctrl[i]->IsSCSI()) {
|
||||
delete m_ctrl[i];
|
||||
m_ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Create a new SCSI controller
|
||||
if (!m_ctrl[i]) {
|
||||
m_ctrl[i] = new SCSIDEV();
|
||||
m_ctrl[i]->Connect(i, m_bus);
|
||||
}
|
||||
}
|
||||
|
||||
// connect all units
|
||||
for (j = 0; j < UnitNum; j++) {
|
||||
unitno = i * UnitNum + j;
|
||||
if (m_disk[unitno]) {
|
||||
// Add the unit connection
|
||||
m_ctrl[i]->SetUnit(j, m_disk[unitno]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Reset
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Rascsi_Manager::Reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Reset all of the controllers
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
if (m_ctrl[i]) {
|
||||
m_ctrl[i]->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the bus
|
||||
m_bus->Reset();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// List Devices
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Rascsi_Manager::ListDevice(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
int id;
|
||||
int un;
|
||||
Disk *pUnit;
|
||||
Filepath filepath;
|
||||
BOOL find;
|
||||
char type[5];
|
||||
|
||||
find = FALSE;
|
||||
type[4] = 0;
|
||||
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
||||
// Initialize ID and unit number
|
||||
id = i / UnitNum;
|
||||
un = i % UnitNum;
|
||||
pUnit = m_disk[i];
|
||||
|
||||
// skip if unit does not exist or null disk
|
||||
if (pUnit == NULL || pUnit->IsNULL()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Output the header
|
||||
if (!find) {
|
||||
FPRT(fp, "\n");
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n");
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
find = TRUE;
|
||||
}
|
||||
|
||||
// ID,UNIT,Type,Device Status
|
||||
type[0] = (char)(pUnit->GetID() >> 24);
|
||||
type[1] = (char)(pUnit->GetID() >> 16);
|
||||
type[2] = (char)(pUnit->GetID() >> 8);
|
||||
type[3] = (char)(pUnit->GetID());
|
||||
FPRT(fp, "| %d | %d | %s | ", id, un, type);
|
||||
|
||||
// mount status output
|
||||
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||||
FPRT(fp, "%s", "HOST BRIDGE");
|
||||
} else {
|
||||
pUnit->GetPath(filepath);
|
||||
FPRT(fp, "%s",
|
||||
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
|
||||
"NO MEDIA" : filepath.GetPath());
|
||||
}
|
||||
|
||||
// Write protection status
|
||||
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
|
||||
FPRT(fp, "(WRITEPROTECT)");
|
||||
}
|
||||
|
||||
// Goto the next line
|
||||
FPRT(fp, "\n");
|
||||
}
|
||||
|
||||
// If there is no controller, find will be null
|
||||
if (!find) {
|
||||
FPRT(fp, "No device is installed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
}
|
||||
|
||||
void Rascsi_Manager::Close(){
|
||||
// Delete the disks
|
||||
for (int i = 0; i < (CtrlMax * UnitNum); i++) {
|
||||
if (m_disk[i]) {
|
||||
delete m_disk[i];
|
||||
m_disk[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the Controllers
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
if (m_ctrl[i]) {
|
||||
delete m_ctrl[i];
|
||||
m_ctrl[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup the Bus
|
||||
m_bus->Cleanup();
|
||||
|
||||
// Discard the GPIOBUS object
|
||||
delete m_bus;
|
||||
}
|
||||
|
||||
BOOL Rascsi_Manager::Init(){
|
||||
|
||||
if(m_instance != nullptr){
|
||||
printf("Can not initialize Rascsi_Manager twice!!!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_instance = new Rascsi_Manager();
|
||||
|
||||
// GPIOBUS creation
|
||||
m_bus = new GPIOBUS();
|
||||
|
||||
// GPIO Initialization
|
||||
if (!m_bus->Init()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Bus Reset
|
||||
m_bus->Reset();
|
||||
|
||||
// Controller initialization
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
m_ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Disk Initialization
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
m_disk[i] = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset
|
||||
Reset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL Rascsi_Manager::Step()
|
||||
{
|
||||
|
||||
m_locked.lock();
|
||||
// Work initialization
|
||||
m_actid = -1;
|
||||
m_phase = BUS::busfree;
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal polling
|
||||
if (m_bus->PollSelectEvent() < 0) {
|
||||
// Stop on interrupt
|
||||
if (errno == EINTR) {
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get the bus
|
||||
m_bus->Aquire();
|
||||
#else
|
||||
m_bus->Aquire();
|
||||
if (!m_bus->GetSEL()) {
|
||||
#if !defined(BAREMETAL)
|
||||
usleep(0);
|
||||
#endif // !BAREMETAL
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
// Wait until BSY is released as there is a possibility for the
|
||||
// initiator to assert it while setting the ID (for up to 3 seconds)
|
||||
if (m_bus->GetBSY()) {
|
||||
m_now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - m_now) < 3 * 1000 * 1000) {
|
||||
m_bus->Aquire();
|
||||
if (!m_bus->GetBSY()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop because it the bus is busy or another device responded
|
||||
if (m_bus->GetBSY() || !m_bus->GetSEL()) {
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Notify all controllers
|
||||
m_data = m_bus->GetDAT();
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
if (!m_ctrl[i] || (m_data & (1 << i)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the target that has moved to the selection phase
|
||||
if (m_ctrl[i]->Process() == BUS::selection) {
|
||||
// Get the target ID
|
||||
m_actid = i;
|
||||
|
||||
// Bus Selection phase
|
||||
m_phase = BUS::selection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return to bus monitoring if the selection phase has not started
|
||||
if (m_phase != BUS::selection) {
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Start target device
|
||||
m_active = TRUE;
|
||||
|
||||
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
||||
// Scheduling policy setting (highest priority)
|
||||
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
||||
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
||||
|
||||
// Loop until the bus is free
|
||||
while (m_running) {
|
||||
// Target drive
|
||||
m_phase = m_ctrl[m_actid]->Process();
|
||||
|
||||
// End when the bus is free
|
||||
if (m_phase == BUS::busfree) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
||||
// Set the scheduling priority back to normal
|
||||
schparam.sched_priority = 0;
|
||||
sched_setscheduler(0, SCHED_OTHER, &schparam);
|
||||
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
||||
|
||||
// End the target travel
|
||||
m_active = FALSE;
|
||||
|
||||
m_locked.unlock();
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
62
src/raspberrypi/rascsi_mgr.h
Normal file
62
src/raspberrypi/rascsi_mgr.h
Normal file
@@ -0,0 +1,62 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ RaSCSI Manager ]
|
||||
//
|
||||
// Any meaningful logic should be included in this file so that it can be
|
||||
// tested using unit tests. The main "rascsi.cpp" file should contain very
|
||||
// little functional code.
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "os.h"
|
||||
#include "scsi.h"
|
||||
#include "fileio.h"
|
||||
#include "disk.h"
|
||||
#include "log.h"
|
||||
#include "xm6.h"
|
||||
#include "gpiobus.h"
|
||||
#include "sasidev_ctrl.h"
|
||||
#include <mutex>
|
||||
|
||||
class Rascsi_Manager{
|
||||
public:
|
||||
static Rascsi_Manager* GetInstance();
|
||||
void MapControler(FILE *fp, Disk **map);
|
||||
void ListDevice(FILE *fp);
|
||||
BOOL Init();
|
||||
void Close();
|
||||
void Reset();
|
||||
BOOL Step();
|
||||
|
||||
static const int CtrlMax = 8; // Maximum number of SCSI controllers
|
||||
static const int UnitNum=2; // Number of units around controller
|
||||
|
||||
|
||||
// TODO: These need to be made private. All of the functionality that is using
|
||||
// them directly should be updated to be issolated.
|
||||
// The Command_Thread class is WAAAAY too tightly coupled to this class.
|
||||
//
|
||||
static SASIDEV *m_ctrl[CtrlMax]; // Controller
|
||||
static Disk *m_disk[CtrlMax * UnitNum]; // Disk
|
||||
static GPIOBUS *m_bus; // GPIO Bus
|
||||
|
||||
|
||||
private:
|
||||
static int m_actid;
|
||||
static BUS::phase_t m_phase;
|
||||
static BYTE m_data;
|
||||
static DWORD m_now;
|
||||
static Rascsi_Manager *m_instance;
|
||||
static BOOL m_active;
|
||||
static BOOL m_running;
|
||||
static std::timed_mutex m_locked;
|
||||
};
|
||||
@@ -10,13 +10,14 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "rasctl_command.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Send Command
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL SendCommand(char *buf)
|
||||
BOOL SendCommand(BYTE *buf)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in server;
|
||||
@@ -39,7 +40,7 @@ BOOL SendCommand(char *buf)
|
||||
// Send the command
|
||||
fp = fdopen(fd, "r+");
|
||||
setvbuf(fp, NULL, _IONBF, 0);
|
||||
fputs(buf, fp);
|
||||
fputs((char*)buf, fp);
|
||||
|
||||
// Receive the message
|
||||
while (1) {
|
||||
@@ -66,20 +67,17 @@ int main(int argc, char* argv[])
|
||||
int opt;
|
||||
int id;
|
||||
int un;
|
||||
int cmd;
|
||||
int type;
|
||||
char *file;
|
||||
BOOL list;
|
||||
int len;
|
||||
char *ext;
|
||||
char buf[BUFSIZ];
|
||||
BYTE buf[BUFSIZ];
|
||||
rasctl_command cmd = rasctl_cmd_invalid;
|
||||
rasctl_dev_type type = rasctl_dev_invalid;
|
||||
Rasctl_Command *rasctl_cmd;
|
||||
|
||||
id = -1;
|
||||
un = 0;
|
||||
cmd = -1;
|
||||
type = -1;
|
||||
file = NULL;
|
||||
list = FALSE;
|
||||
|
||||
// Display help
|
||||
if (argc < 2) {
|
||||
@@ -115,23 +113,27 @@ int main(int argc, char* argv[])
|
||||
switch (optarg[0]) {
|
||||
case 'a': // ATTACH
|
||||
case 'A':
|
||||
cmd = 0;
|
||||
cmd = rasctl_cmd_attach;
|
||||
break;
|
||||
case 'd': // DETACH
|
||||
case 'D':
|
||||
cmd = 1;
|
||||
cmd = rasctl_cmd_detach;
|
||||
break;
|
||||
case 'i': // INSERT
|
||||
case 'I':
|
||||
cmd = 2;
|
||||
cmd = rasctl_cmd_insert;
|
||||
break;
|
||||
case 'e': // EJECT
|
||||
case 'E':
|
||||
cmd = 3;
|
||||
cmd = rasctl_cmd_eject;
|
||||
break;
|
||||
case 'p': // PROTECT
|
||||
case 'P':
|
||||
cmd = 4;
|
||||
cmd = rasctl_cmd_protect;
|
||||
break;
|
||||
case 's': // Shutdown the rasci service
|
||||
case 'S':
|
||||
cmd = rasctl_cmd_shutdown;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -140,41 +142,36 @@ int main(int argc, char* argv[])
|
||||
switch (optarg[0]) {
|
||||
case 's': // HD(SASI)
|
||||
case 'S':
|
||||
type = rasctl_dev_sasi_hd;
|
||||
break;
|
||||
case 'h': // HD(SCSI)
|
||||
case 'H':
|
||||
type = 0;
|
||||
type = rasctl_dev_scsi_hd;
|
||||
break;
|
||||
case 'm': // MO
|
||||
case 'M':
|
||||
type = 2;
|
||||
type = rasctl_dev_mo;
|
||||
break;
|
||||
case 'c': // CD
|
||||
case 'C':
|
||||
type = 3;
|
||||
type = rasctl_dev_cd;
|
||||
break;
|
||||
case 'b': // BRIDGE
|
||||
case 'B':
|
||||
type = 4;
|
||||
type = rasctl_dev_br;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
list = TRUE;
|
||||
cmd = rasctl_cmd_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// List display only
|
||||
if (id < 0 && cmd < 0 && type < 0 && file == NULL && list) {
|
||||
sprintf(buf, "list\n");
|
||||
SendCommand(buf);
|
||||
exit(0);
|
||||
}
|
||||
if((cmd != rasctl_cmd_list) && (cmd != rasctl_cmd_shutdown)){
|
||||
|
||||
// Check the ID number
|
||||
if (id < 0 || id > 7) {
|
||||
@@ -189,42 +186,46 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
// Command check
|
||||
if (cmd < 0) {
|
||||
cmd = 0; // Default command is ATTATCH
|
||||
if (cmd == rasctl_cmd_invalid) {
|
||||
cmd = rasctl_cmd_attach; // Default command is ATTATCH
|
||||
}
|
||||
|
||||
// Type Check
|
||||
if (cmd == 0 && type < 0) {
|
||||
if (cmd == rasctl_cmd_attach && type == rasctl_dev_invalid) {
|
||||
|
||||
// Try to determine the file type from the extension
|
||||
len = file ? strlen(file) : 0;
|
||||
if (len > 4 && file[len - 4] == '.') {
|
||||
ext = &file[len - 3];
|
||||
if (xstrcasecmp(ext, "hdf") == 0 ||
|
||||
xstrcasecmp(ext, "hds") == 0 ||
|
||||
xstrcasecmp(ext, "hdn") == 0 ||
|
||||
if (xstrcasecmp(ext, "hdf") == 0){
|
||||
type = rasctl_dev_sasi_hd;
|
||||
}else if(xstrcasecmp(ext, "hds") == 0 ||
|
||||
xstrcasecmp(ext, "hdi") == 0 ||
|
||||
xstrcasecmp(ext, "nhd") == 0 ||
|
||||
xstrcasecmp(ext, "hda") == 0) {
|
||||
// HD(SASI/SCSI)
|
||||
type = 0;
|
||||
xstrcasecmp(ext, "nhd") == 0){
|
||||
type = rasctl_dev_scsi_hd;
|
||||
}else if(xstrcasecmp(ext, "hdn") == 0) {
|
||||
// NEC HD(SASI/SCSI)
|
||||
type = rasctl_dev_scsi_hd_appl;
|
||||
}else if(xstrcasecmp(ext, "hda") == 0) {
|
||||
// Apple HD(SASI/SCSI)
|
||||
type = rasctl_dev_scsi_hd_appl;
|
||||
}else if (xstrcasecmp(ext, "mos") == 0) {
|
||||
// MO
|
||||
type = 2;
|
||||
type = rasctl_dev_mo;
|
||||
}else if (xstrcasecmp(ext, "iso") == 0) {
|
||||
// CD
|
||||
type = 3;
|
||||
type = rasctl_dev_cd;
|
||||
}
|
||||
}
|
||||
|
||||
if (type < 0) {
|
||||
if (type == rasctl_dev_invalid) {
|
||||
fprintf(stderr, "Error : Invalid type\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
// File check (command is ATTACH and type is HD)
|
||||
if (cmd == 0 && type >= 0 && type <= 1) {
|
||||
if ((cmd == rasctl_cmd_attach) && (Rasctl_Command::rasctl_dev_is_hd(type))){
|
||||
if (!file) {
|
||||
fprintf(stderr, "Error : Invalid file path\n");
|
||||
exit(EINVAL);
|
||||
@@ -232,30 +233,35 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
// File check (command is INSERT)
|
||||
if (cmd == 2) {
|
||||
if (cmd == rasctl_cmd_insert) {
|
||||
if (!file) {
|
||||
fprintf(stderr, "Error : Invalid file path\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
// Set unnecessary type to 0
|
||||
if (type < 0) {
|
||||
type = 0;
|
||||
// If we don't know what the type is, default to SCSI HD
|
||||
if (type == rasctl_dev_invalid) {
|
||||
type = rasctl_dev_scsi_hd;
|
||||
}
|
||||
}
|
||||
|
||||
rasctl_cmd = new Rasctl_Command();
|
||||
rasctl_cmd->type = type;
|
||||
rasctl_cmd->un = un;
|
||||
rasctl_cmd->id = id;
|
||||
rasctl_cmd->cmd = cmd;
|
||||
if(file){
|
||||
strncpy(rasctl_cmd->file,file,_MAX_PATH);
|
||||
}
|
||||
|
||||
// Generate the command and send it
|
||||
sprintf(buf, "%d %d %d %d %s\n", id, un, cmd, type, file ? file : "-");
|
||||
rasctl_cmd->Serialize(buf,BUFSIZ);
|
||||
|
||||
if (!SendCommand(buf)) {
|
||||
exit(ENOTCONN);
|
||||
}
|
||||
|
||||
// Display the list
|
||||
if (list) {
|
||||
sprintf(buf, "list\n");
|
||||
SendCommand(buf);
|
||||
}
|
||||
|
||||
// All done!
|
||||
exit(0);
|
||||
}
|
||||
|
||||
72
src/raspberrypi/rasctl_command.cpp
Normal file
72
src/raspberrypi/rasctl_command.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "rasctl_command.h"
|
||||
|
||||
//const char* Rasctl_Command::m_delimiter = "\x1E"; // Record separator charater
|
||||
const char* Rasctl_Command::m_delimiter = " "; // Record separator charater
|
||||
|
||||
void Rasctl_Command::Serialize(BYTE *buff, int max_buff_size){
|
||||
snprintf((char*)buff, max_buff_size, "%d%s%d%s%d%s%d%s%s%s",
|
||||
this->id, this->m_delimiter,
|
||||
this->un, this->m_delimiter,
|
||||
this->cmd, this->m_delimiter,
|
||||
this->type, this->m_delimiter,
|
||||
this->file, this->m_delimiter);
|
||||
}
|
||||
|
||||
Rasctl_Command* Rasctl_Command::DeSerialize(BYTE* buff, int size){
|
||||
Rasctl_Command *return_command = new Rasctl_Command();
|
||||
char err_message[256];
|
||||
char *cur_token;
|
||||
char *command = (char*)buff;
|
||||
serial_token_order cur_token_idx = serial_token_first_token;
|
||||
|
||||
cur_token = strtok(command, m_delimiter);
|
||||
// Loop through all of the tokens in the message
|
||||
while (cur_token != NULL){
|
||||
switch(cur_token_idx){
|
||||
case serial_token_cmd:
|
||||
return_command->cmd = (rasctl_command)atoi(cur_token);
|
||||
break;
|
||||
case serial_token_type:
|
||||
return_command->type = (rasctl_dev_type)atoi(cur_token);
|
||||
break;
|
||||
case serial_token_file_name:
|
||||
strncpy(return_command->file,cur_token,_MAX_PATH);
|
||||
break;
|
||||
case serial_token_id:
|
||||
return_command->id = atoi(cur_token);
|
||||
break;
|
||||
case serial_token_un:
|
||||
return_command->un = atoi(cur_token);
|
||||
break;
|
||||
default:
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
snprintf(&err_message[i*2], sizeof(err_message), "%02X", buff[i]);
|
||||
}
|
||||
printf("Received too many tokens: %s", err_message);
|
||||
free(return_command);
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
cur_token_idx = (serial_token_order)((int)cur_token_idx + 1);
|
||||
}
|
||||
|
||||
if(cur_token_idx != serial_token_last_token)
|
||||
{
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
snprintf(&err_message[i*2], sizeof(err_message), "%02X", buff[i]);
|
||||
}
|
||||
printf("Received too few tokens: %s", err_message);
|
||||
free(return_command);
|
||||
}
|
||||
|
||||
return return_command;
|
||||
}
|
||||
|
||||
|
||||
BOOL Rasctl_Command::rasctl_dev_is_hd(rasctl_dev_type type)
|
||||
{
|
||||
return ((type == rasctl_dev_scsi_hd) || (type == rasctl_dev_sasi_hd) ||
|
||||
(type == rasctl_dev_scsi_hd_appl) || (type == rasctl_dev_scsi_hd_nec));
|
||||
}
|
||||
66
src/raspberrypi/rasctl_command.h
Normal file
66
src/raspberrypi/rasctl_command.h
Normal file
@@ -0,0 +1,66 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// [ Send Control Command ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "os.h"
|
||||
|
||||
enum rasctl_command : int {
|
||||
rasctl_cmd_invalid = -1,
|
||||
rasctl_cmd_attach = 0,
|
||||
rasctl_cmd_detach = 1,
|
||||
rasctl_cmd_insert = 2,
|
||||
rasctl_cmd_eject = 3,
|
||||
rasctl_cmd_protect = 4,
|
||||
rasctl_cmd_list = 5,
|
||||
rasctl_cmd_op = 6,
|
||||
rasctl_cmd_shutdown = 7,
|
||||
};
|
||||
|
||||
enum rasctl_dev_type : int {
|
||||
rasctl_dev_invalid = -1,
|
||||
rasctl_dev_scsi_hd = 0,
|
||||
rasctl_dev_sasi_hd = 0,
|
||||
rasctl_dev_mo = 2,
|
||||
rasctl_dev_cd = 3,
|
||||
rasctl_dev_br = 4,
|
||||
rasctl_dev_scsi_hd_appl = 5,
|
||||
rasctl_dev_scsi_hd_nec = 6,
|
||||
};
|
||||
|
||||
|
||||
class Rasctl_Command{
|
||||
public:
|
||||
void Serialize(BYTE *buff, int max_buff_size);
|
||||
static Rasctl_Command* DeSerialize(BYTE* buff, int size);
|
||||
|
||||
rasctl_command cmd = rasctl_cmd_invalid;
|
||||
rasctl_dev_type type = rasctl_dev_invalid;
|
||||
int id = -1;
|
||||
int un = -1;
|
||||
char file[_MAX_PATH];
|
||||
|
||||
static BOOL rasctl_dev_is_hd(rasctl_dev_type dev);
|
||||
|
||||
private:
|
||||
static const char* m_delimiter; // Record separator charater
|
||||
|
||||
enum serial_token_order : int {
|
||||
serial_token_first_token = 0,
|
||||
serial_token_id = 0,
|
||||
serial_token_un = 1,
|
||||
serial_token_cmd = 2,
|
||||
serial_token_type = 3,
|
||||
serial_token_file_name = 4,
|
||||
serial_token_last_token = 5,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user