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 \
|
scsi.cpp \
|
||||||
gpiobus.cpp \
|
gpiobus.cpp \
|
||||||
filepath.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 ./controllers -name '*.cpp'))
|
||||||
SRC_RASCSI += $(notdir $(shell find ./disks -name '*.cpp'))
|
SRC_RASCSI += $(notdir $(shell find ./disks -name '*.cpp'))
|
||||||
|
|
||||||
SRC_RASCTL = \
|
SRC_RASCTL = \
|
||||||
rasctl.cpp
|
rasctl.cpp\
|
||||||
|
rasctl_command.cpp
|
||||||
|
|
||||||
SRC_RASDUMP = \
|
SRC_RASDUMP = \
|
||||||
rasdump.cpp \
|
rasdump.cpp \
|
||||||
@@ -107,9 +112,11 @@ ALL: all
|
|||||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt
|
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt
|
||||||
|
|
||||||
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) $(BINDIR)
|
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) $(BINDIR)
|
||||||
|
@echo -- Linking $(RASCSI)
|
||||||
$(CXX) -o $@ $(OBJ_RASCSI) -lpthread
|
$(CXX) -o $@ $(OBJ_RASCSI) -lpthread
|
||||||
|
|
||||||
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) $(BINDIR)
|
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) $(BINDIR)
|
||||||
|
@echo -- Linking $(RASCTL)
|
||||||
$(CXX) -o $@ $(OBJ_RASCTL)
|
$(CXX) -o $@ $(OBJ_RASCTL)
|
||||||
|
|
||||||
$(RASDUMP): $(OBJ_RASDUMP) $(BINDIR)
|
$(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)
|
#if !defined(log_h)
|
||||||
#define 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 xstrcasecmp strcasecmp
|
||||||
#define xstrncasecmp strncasecmp
|
#define xstrncasecmp strncasecmp
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Pin the thread to a specific CPU
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void FixCpu(int cpu);
|
||||||
|
|
||||||
#endif // os_h
|
#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 "os.h"
|
||||||
|
#include "rasctl_command.h"
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Send Command
|
// Send Command
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL SendCommand(char *buf)
|
BOOL SendCommand(BYTE *buf)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct sockaddr_in server;
|
struct sockaddr_in server;
|
||||||
@@ -39,7 +40,7 @@ BOOL SendCommand(char *buf)
|
|||||||
// Send the command
|
// Send the command
|
||||||
fp = fdopen(fd, "r+");
|
fp = fdopen(fd, "r+");
|
||||||
setvbuf(fp, NULL, _IONBF, 0);
|
setvbuf(fp, NULL, _IONBF, 0);
|
||||||
fputs(buf, fp);
|
fputs((char*)buf, fp);
|
||||||
|
|
||||||
// Receive the message
|
// Receive the message
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -66,20 +67,17 @@ int main(int argc, char* argv[])
|
|||||||
int opt;
|
int opt;
|
||||||
int id;
|
int id;
|
||||||
int un;
|
int un;
|
||||||
int cmd;
|
|
||||||
int type;
|
|
||||||
char *file;
|
char *file;
|
||||||
BOOL list;
|
|
||||||
int len;
|
int len;
|
||||||
char *ext;
|
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;
|
id = -1;
|
||||||
un = 0;
|
un = 0;
|
||||||
cmd = -1;
|
|
||||||
type = -1;
|
|
||||||
file = NULL;
|
file = NULL;
|
||||||
list = FALSE;
|
|
||||||
|
|
||||||
// Display help
|
// Display help
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@@ -115,23 +113,27 @@ int main(int argc, char* argv[])
|
|||||||
switch (optarg[0]) {
|
switch (optarg[0]) {
|
||||||
case 'a': // ATTACH
|
case 'a': // ATTACH
|
||||||
case 'A':
|
case 'A':
|
||||||
cmd = 0;
|
cmd = rasctl_cmd_attach;
|
||||||
break;
|
break;
|
||||||
case 'd': // DETACH
|
case 'd': // DETACH
|
||||||
case 'D':
|
case 'D':
|
||||||
cmd = 1;
|
cmd = rasctl_cmd_detach;
|
||||||
break;
|
break;
|
||||||
case 'i': // INSERT
|
case 'i': // INSERT
|
||||||
case 'I':
|
case 'I':
|
||||||
cmd = 2;
|
cmd = rasctl_cmd_insert;
|
||||||
break;
|
break;
|
||||||
case 'e': // EJECT
|
case 'e': // EJECT
|
||||||
case 'E':
|
case 'E':
|
||||||
cmd = 3;
|
cmd = rasctl_cmd_eject;
|
||||||
break;
|
break;
|
||||||
case 'p': // PROTECT
|
case 'p': // PROTECT
|
||||||
case 'P':
|
case 'P':
|
||||||
cmd = 4;
|
cmd = rasctl_cmd_protect;
|
||||||
|
break;
|
||||||
|
case 's': // Shutdown the rasci service
|
||||||
|
case 'S':
|
||||||
|
cmd = rasctl_cmd_shutdown;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -140,41 +142,36 @@ int main(int argc, char* argv[])
|
|||||||
switch (optarg[0]) {
|
switch (optarg[0]) {
|
||||||
case 's': // HD(SASI)
|
case 's': // HD(SASI)
|
||||||
case 'S':
|
case 'S':
|
||||||
|
type = rasctl_dev_sasi_hd;
|
||||||
|
break;
|
||||||
case 'h': // HD(SCSI)
|
case 'h': // HD(SCSI)
|
||||||
case 'H':
|
case 'H':
|
||||||
type = 0;
|
type = rasctl_dev_scsi_hd;
|
||||||
break;
|
break;
|
||||||
case 'm': // MO
|
case 'm': // MO
|
||||||
case 'M':
|
case 'M':
|
||||||
type = 2;
|
type = rasctl_dev_mo;
|
||||||
break;
|
break;
|
||||||
case 'c': // CD
|
case 'c': // CD
|
||||||
case 'C':
|
case 'C':
|
||||||
type = 3;
|
type = rasctl_dev_cd;
|
||||||
break;
|
break;
|
||||||
case 'b': // BRIDGE
|
case 'b': // BRIDGE
|
||||||
case 'B':
|
case 'B':
|
||||||
type = 4;
|
type = rasctl_dev_br;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
file = optarg;
|
file = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
list = TRUE;
|
cmd = rasctl_cmd_list;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List display only
|
if((cmd != rasctl_cmd_list) && (cmd != rasctl_cmd_shutdown)){
|
||||||
if (id < 0 && cmd < 0 && type < 0 && file == NULL && list) {
|
|
||||||
sprintf(buf, "list\n");
|
|
||||||
SendCommand(buf);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the ID number
|
// Check the ID number
|
||||||
if (id < 0 || id > 7) {
|
if (id < 0 || id > 7) {
|
||||||
@@ -189,42 +186,46 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Command check
|
// Command check
|
||||||
if (cmd < 0) {
|
if (cmd == rasctl_cmd_invalid) {
|
||||||
cmd = 0; // Default command is ATTATCH
|
cmd = rasctl_cmd_attach; // Default command is ATTATCH
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type Check
|
// 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
|
// Try to determine the file type from the extension
|
||||||
len = file ? strlen(file) : 0;
|
len = file ? strlen(file) : 0;
|
||||||
if (len > 4 && file[len - 4] == '.') {
|
if (len > 4 && file[len - 4] == '.') {
|
||||||
ext = &file[len - 3];
|
ext = &file[len - 3];
|
||||||
if (xstrcasecmp(ext, "hdf") == 0 ||
|
if (xstrcasecmp(ext, "hdf") == 0){
|
||||||
xstrcasecmp(ext, "hds") == 0 ||
|
type = rasctl_dev_sasi_hd;
|
||||||
xstrcasecmp(ext, "hdn") == 0 ||
|
}else if(xstrcasecmp(ext, "hds") == 0 ||
|
||||||
xstrcasecmp(ext, "hdi") == 0 ||
|
xstrcasecmp(ext, "hdi") == 0 ||
|
||||||
xstrcasecmp(ext, "nhd") == 0 ||
|
xstrcasecmp(ext, "nhd") == 0){
|
||||||
xstrcasecmp(ext, "hda") == 0) {
|
type = rasctl_dev_scsi_hd;
|
||||||
// HD(SASI/SCSI)
|
}else if(xstrcasecmp(ext, "hdn") == 0) {
|
||||||
type = 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) {
|
}else if (xstrcasecmp(ext, "mos") == 0) {
|
||||||
// MO
|
// MO
|
||||||
type = 2;
|
type = rasctl_dev_mo;
|
||||||
}else if (xstrcasecmp(ext, "iso") == 0) {
|
}else if (xstrcasecmp(ext, "iso") == 0) {
|
||||||
// CD
|
// CD
|
||||||
type = 3;
|
type = rasctl_dev_cd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type < 0) {
|
if (type == rasctl_dev_invalid) {
|
||||||
fprintf(stderr, "Error : Invalid type\n");
|
fprintf(stderr, "Error : Invalid type\n");
|
||||||
exit(EINVAL);
|
exit(EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// File check (command is ATTACH and type is HD)
|
// 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) {
|
if (!file) {
|
||||||
fprintf(stderr, "Error : Invalid file path\n");
|
fprintf(stderr, "Error : Invalid file path\n");
|
||||||
exit(EINVAL);
|
exit(EINVAL);
|
||||||
@@ -232,30 +233,35 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// File check (command is INSERT)
|
// File check (command is INSERT)
|
||||||
if (cmd == 2) {
|
if (cmd == rasctl_cmd_insert) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
fprintf(stderr, "Error : Invalid file path\n");
|
fprintf(stderr, "Error : Invalid file path\n");
|
||||||
exit(EINVAL);
|
exit(EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set unnecessary type to 0
|
// If we don't know what the type is, default to SCSI HD
|
||||||
if (type < 0) {
|
if (type == rasctl_dev_invalid) {
|
||||||
type = 0;
|
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
|
// 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)) {
|
if (!SendCommand(buf)) {
|
||||||
exit(ENOTCONN);
|
exit(ENOTCONN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the list
|
|
||||||
if (list) {
|
|
||||||
sprintf(buf, "list\n");
|
|
||||||
SendCommand(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done!
|
// All done!
|
||||||
exit(0);
|
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