mirror of
https://github.com/thewesker/RASCSI.git
synced 2025-12-20 12:21:10 -05:00
Start to back out some changes. Just include command processing changes
This commit is contained in:
@@ -54,7 +54,6 @@ SRC_RASCSI = \
|
|||||||
gpiobus.cpp \
|
gpiobus.cpp \
|
||||||
filepath.cpp \
|
filepath.cpp \
|
||||||
fileio.cpp\
|
fileio.cpp\
|
||||||
rascsi_mgr.cpp\
|
|
||||||
command_thread.cpp\
|
command_thread.cpp\
|
||||||
os.cpp\
|
os.cpp\
|
||||||
rasctl_command.cpp
|
rasctl_command.cpp
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "rasctl_command.h"
|
#include "rasctl_command.h"
|
||||||
#include "rascsi_mgr.h"
|
|
||||||
#include "sasihd.h"
|
#include "sasihd.h"
|
||||||
#include "scsihd.h"
|
#include "scsihd.h"
|
||||||
#include "scsihd_nec.h"
|
#include "scsihd_nec.h"
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
//
|
//
|
||||||
// Powered by XM6 TypeG Technology.
|
// Powered by XM6 TypeG Technology.
|
||||||
// Copyright (C) 2016-2020 GIMONS
|
// Copyright (C) 2016-2020 GIMONS
|
||||||
// Copyright (C) akuker
|
|
||||||
//
|
|
||||||
// [ RaSCSI main ]
|
// [ RaSCSI main ]
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@@ -27,41 +25,35 @@
|
|||||||
#include "controllers/sasidev_ctrl.h"
|
#include "controllers/sasidev_ctrl.h"
|
||||||
#include "gpiobus.h"
|
#include "gpiobus.h"
|
||||||
#include "command_thread.h"
|
#include "command_thread.h"
|
||||||
#include "rascsi_mgr.h"
|
|
||||||
|
|
||||||
#include "sasidev_ctrl.h"
|
|
||||||
#include "scsidev_ctrl.h"
|
|
||||||
|
|
||||||
#include "sasihd.h"
|
|
||||||
#include "scsihd.h"
|
|
||||||
#include "scsihd_apple.h"
|
|
||||||
#include "scsihd_nec.h"
|
|
||||||
#include "scsicd.h"
|
|
||||||
#include "scsimo.h"
|
|
||||||
#include "scsi_host_bridge.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Constant declarations
|
// Constant declarations
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
#define CtrlMax 8 // Maximum number of SCSI controllers
|
||||||
|
#define UnitNum 2 // Number of units around controller
|
||||||
|
#ifdef BAREMETAL
|
||||||
|
#define FPRT(fp, ...) printf( __VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
||||||
|
#endif // BAREMETAL
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Variable declarations
|
// Variable declarations
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
static volatile BOOL running; // Running flag
|
||||||
|
static volatile BOOL active; // Processing flag
|
||||||
|
SASIDEV *ctrl[CtrlMax]; // Controller
|
||||||
|
Disk *disk[CtrlMax * UnitNum]; // Disk
|
||||||
|
GPIOBUS *bus; // GPIO Bus
|
||||||
#ifdef BAREMETAL
|
#ifdef BAREMETAL
|
||||||
FATFS fatfs; // FatFS
|
FATFS fatfs; // FatFS
|
||||||
#else
|
#else
|
||||||
#endif // BAREMETAL
|
#endif // BAREMETAL
|
||||||
|
|
||||||
#ifndef CONNECT_DESC
|
|
||||||
#define CONNECT_DESC "UNKNOWN"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef BAREMETAL
|
#ifndef BAREMETAL
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@@ -71,7 +63,7 @@ FATFS fatfs; // FatFS
|
|||||||
void KillHandler(int sig)
|
void KillHandler(int sig)
|
||||||
{
|
{
|
||||||
// Stop instruction
|
// Stop instruction
|
||||||
Rascsi_Manager::Stop();
|
running = FALSE;
|
||||||
}
|
}
|
||||||
#endif // BAREMETAL
|
#endif // BAREMETAL
|
||||||
|
|
||||||
@@ -93,7 +85,6 @@ void Banner(int argc, char* argv[])
|
|||||||
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
||||||
FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n");
|
FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n");
|
||||||
FPRT(stdout,"Connect type : %s\n", CONNECT_DESC);
|
FPRT(stdout,"Connect type : %s\n", CONNECT_DESC);
|
||||||
FPRT(stdout,"Build on %s at %s\n", __DATE__, __TIME__);
|
|
||||||
|
|
||||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
||||||
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||||
@@ -127,17 +118,9 @@ void Banner(int argc, char* argv[])
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL Init()
|
BOOL Init()
|
||||||
{
|
{
|
||||||
printf("Rascsi_Manager Init\n");
|
int i;
|
||||||
if(!Rascsi_Manager::Init()){
|
|
||||||
printf("\tRascsi_Manager FAILED!!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Command_Thread Init\n");
|
#ifndef BAREMETAL
|
||||||
if(!Command_Thread::Init()){
|
|
||||||
printf("\tCommand_Thread FAILED!!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interrupt handler settings
|
// Interrupt handler settings
|
||||||
if (signal(SIGINT, KillHandler) == SIG_ERR) {
|
if (signal(SIGINT, KillHandler) == SIG_ERR) {
|
||||||
@@ -149,6 +132,38 @@ BOOL Init()
|
|||||||
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
|
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
#endif // BAREMETAL
|
||||||
|
|
||||||
|
// GPIOBUS creation
|
||||||
|
bus = new GPIOBUS();
|
||||||
|
|
||||||
|
// GPIO Initialization
|
||||||
|
if (!bus->Init()) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bus Reset
|
||||||
|
bus->Reset();
|
||||||
|
|
||||||
|
// Controller initialization
|
||||||
|
for (i = 0; i < CtrlMax; i++) {
|
||||||
|
ctrl[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disk Initialization
|
||||||
|
for (i = 0; i < CtrlMax; i++) {
|
||||||
|
disk[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other
|
||||||
|
running = FALSE;
|
||||||
|
active = FALSE;
|
||||||
|
|
||||||
|
printf("Command_Thread Init\n");
|
||||||
|
if(!Command_Thread::Init()){
|
||||||
|
printf("\tCommand_Thread FAILED!!\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -160,13 +175,243 @@ BOOL Init()
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void Cleanup()
|
void Cleanup()
|
||||||
{
|
{
|
||||||
Rascsi_Manager::Close();
|
int i;
|
||||||
|
|
||||||
|
// Delete the disks
|
||||||
|
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
||||||
|
if (disk[i]) {
|
||||||
|
delete disk[i];
|
||||||
|
disk[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the Controllers
|
||||||
|
for (i = 0; i < CtrlMax; i++) {
|
||||||
|
if (ctrl[i]) {
|
||||||
|
delete ctrl[i];
|
||||||
|
ctrl[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup the Bus
|
||||||
|
bus->Cleanup();
|
||||||
|
|
||||||
|
// Discard the GPIOBUS object
|
||||||
|
delete bus;
|
||||||
|
|
||||||
#ifndef BAREMETAL
|
#ifndef BAREMETAL
|
||||||
|
// Close the command socket
|
||||||
Command_Thread::Close();
|
Command_Thread::Close();
|
||||||
#endif // BAREMETAL
|
#endif // BAREMETAL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Reset
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Reset all of the controllers
|
||||||
|
for (i = 0; i < CtrlMax; i++) {
|
||||||
|
if (ctrl[i]) {
|
||||||
|
ctrl[i]->Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the bus
|
||||||
|
bus->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// List Devices
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void 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 = 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Controller Mapping
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void 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 (disk[unitno] != map[unitno]) {
|
||||||
|
// Check if the original unit exists
|
||||||
|
if (disk[unitno]) {
|
||||||
|
// Disconnect it from the controller
|
||||||
|
if (ctrl[i]) {
|
||||||
|
ctrl[i]->SetUnit(j, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the Unit
|
||||||
|
delete disk[unitno];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup a new unit
|
||||||
|
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 (disk[unitno]) {
|
||||||
|
if (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 (ctrl[i]) {
|
||||||
|
ctrl[i]->SetUnit(j, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no units connected
|
||||||
|
if (sasi_num == 0 && scsi_num == 0) {
|
||||||
|
if (ctrl[i]) {
|
||||||
|
delete ctrl[i];
|
||||||
|
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 (ctrl[i] && !ctrl[i]->IsSASI()) {
|
||||||
|
delete ctrl[i];
|
||||||
|
ctrl[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new SASI controller
|
||||||
|
if (!ctrl[i]) {
|
||||||
|
ctrl[i] = new SASIDEV();
|
||||||
|
ctrl[i]->Connect(i, bus);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Only SCSI Unit(s)
|
||||||
|
|
||||||
|
// Release the controller if it is not SCSI
|
||||||
|
if (ctrl[i] && !ctrl[i]->IsSCSI()) {
|
||||||
|
delete ctrl[i];
|
||||||
|
ctrl[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new SCSI controller
|
||||||
|
if (!ctrl[i]) {
|
||||||
|
ctrl[i] = new SCSIDEV();
|
||||||
|
ctrl[i]->Connect(i, bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect all units
|
||||||
|
for (j = 0; j < UnitNum; j++) {
|
||||||
|
unitno = i * UnitNum + j;
|
||||||
|
if (disk[unitno]) {
|
||||||
|
// Add the unit connection
|
||||||
|
ctrl[i]->SetUnit(j, disk[unitno]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Main processing
|
// Main processing
|
||||||
@@ -181,9 +426,13 @@ int startrascsi(void)
|
|||||||
#else
|
#else
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int i=0;
|
|
||||||
#endif // BAREMETAL
|
#endif // BAREMETAL
|
||||||
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
int actid;
|
||||||
|
DWORD now;
|
||||||
|
BUS::phase_t phase;
|
||||||
|
BYTE data;
|
||||||
#ifndef BAREMETAL
|
#ifndef BAREMETAL
|
||||||
struct sched_param schparam;
|
struct sched_param schparam;
|
||||||
#endif // BAREMETAL
|
#endif // BAREMETAL
|
||||||
@@ -198,24 +447,23 @@ int main(int argc, char* argv[])
|
|||||||
goto init_exit;
|
goto init_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
Reset();
|
||||||
|
|
||||||
#ifdef BAREMETAL
|
#ifdef BAREMETAL
|
||||||
// BUSY assert (to hold the host side)
|
// BUSY assert (to hold the host side)
|
||||||
Rascsi_Manager::m_bus->SetBSY(TRUE);
|
bus->SetBSY(TRUE);
|
||||||
|
|
||||||
// Argument parsing
|
// Argument parsing
|
||||||
if (!Command_Thread::ParseConfig(argc, argv)) {
|
if (!Command_Thread::ParseConfig(argc, argv)) {
|
||||||
ret = EINVAL;
|
ret = EINVAL;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the busy signal
|
// Release the busy signal
|
||||||
Rascsi_Manager::m_bus->SetBSY(FALSE);
|
bus->SetBSY(FALSE);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For non-baremetal versions, we won't process the startup arguments... yet
|
|
||||||
printf("Here1\n");
|
|
||||||
|
|
||||||
#ifndef BAREMETAL
|
#ifndef BAREMETAL
|
||||||
// Set the affinity to a specific processor core
|
// Set the affinity to a specific processor core
|
||||||
FixCpu(3);
|
FixCpu(3);
|
||||||
@@ -227,11 +475,105 @@ int main(int argc, char* argv[])
|
|||||||
#endif // USE_SEL_EVENT_ENABLE
|
#endif // USE_SEL_EVENT_ENABLE
|
||||||
#endif // BAREMETAL
|
#endif // BAREMETAL
|
||||||
|
|
||||||
printf("entering main loop \n");
|
// Start execution
|
||||||
|
running = TRUE;
|
||||||
|
|
||||||
// Main Loop
|
// Main Loop
|
||||||
while (Rascsi_Manager::IsRunning()) {
|
while (running) {
|
||||||
printf("step %d\n", i++);
|
// Work initialization
|
||||||
Rascsi_Manager::Step();
|
actid = -1;
|
||||||
|
phase = BUS::busfree;
|
||||||
|
|
||||||
|
#ifdef USE_SEL_EVENT_ENABLE
|
||||||
|
// SEL signal polling
|
||||||
|
if (bus->PollSelectEvent() < 0) {
|
||||||
|
// Stop on interrupt
|
||||||
|
if (errno == EINTR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the bus
|
||||||
|
bus->Aquire();
|
||||||
|
#else
|
||||||
|
bus->Aquire();
|
||||||
|
if (!bus->GetSEL()) {
|
||||||
|
#if !defined(BAREMETAL)
|
||||||
|
usleep(0);
|
||||||
|
#endif // !BAREMETAL
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#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 (bus->GetBSY()) {
|
||||||
|
now = SysTimer::GetTimerLow();
|
||||||
|
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
||||||
|
bus->Aquire();
|
||||||
|
if (!bus->GetBSY()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop because it the bus is busy or another device responded
|
||||||
|
if (bus->GetBSY() || !bus->GetSEL()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify all controllers
|
||||||
|
data = bus->GetDAT();
|
||||||
|
for (i = 0; i < CtrlMax; i++) {
|
||||||
|
if (!ctrl[i] || (data & (1 << i)) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the target that has moved to the selection phase
|
||||||
|
if (ctrl[i]->Process() == BUS::selection) {
|
||||||
|
// Get the target ID
|
||||||
|
actid = i;
|
||||||
|
|
||||||
|
// Bus Selection phase
|
||||||
|
phase = BUS::selection;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to bus monitoring if the selection phase has not started
|
||||||
|
if (phase != BUS::selection) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start target device
|
||||||
|
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 (running) {
|
||||||
|
// Target drive
|
||||||
|
phase = ctrl[actid]->Process();
|
||||||
|
|
||||||
|
// End when the bus is free
|
||||||
|
if (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
|
||||||
|
active = FALSE;
|
||||||
}
|
}
|
||||||
printf("Exited main loop\n");
|
printf("Exited main loop\n");
|
||||||
|
|
||||||
|
|||||||
@@ -1,403 +0,0 @@
|
|||||||
#include "rascsi_mgr.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "sasidev_ctrl.h"
|
|
||||||
#include "scsidev_ctrl.h"
|
|
||||||
|
|
||||||
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;
|
|
||||||
BOOL Rascsi_Manager::m_initialized = FALSE;
|
|
||||||
|
|
||||||
BOOL Rascsi_Manager::AttachDevice(FILE *fp, Disk *disk, int id, int unit_num){
|
|
||||||
BOOL result;
|
|
||||||
m_locked.lock();
|
|
||||||
result = AttachDevicePrivate(fp, disk, id, unit_num);
|
|
||||||
m_locked.unlock();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL Rascsi_Manager::DetachDevice(FILE *fp, int id, int unit_num){
|
|
||||||
BOOL result;
|
|
||||||
m_locked.lock();
|
|
||||||
result = DetachDevicePrivate(fp, id, unit_num);
|
|
||||||
m_locked.unlock();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL Rascsi_Manager::AttachDevicePrivate(FILE *fp, Disk *disk, int id, int unit_num)
|
|
||||||
{
|
|
||||||
Rascsi_Device_Mode_e cur_mode = GetCurrentDeviceMode();
|
|
||||||
int unitno = (id * UnitNum) + unit_num;
|
|
||||||
|
|
||||||
if((disk->IsSASI() && (cur_mode == rascsi_device_scsi_mode)) ||
|
|
||||||
(!disk->IsSCSI() && (cur_mode == rascsi_device_sasi_mode))){
|
|
||||||
FPRT(fp, "Warning: Can't mix SASI and SCSI devices!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if something already exists at that SCSI ID / Unit Number
|
|
||||||
if (m_disk[unitno]) {
|
|
||||||
DetachDevicePrivate(fp,id,unit_num);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the new unit
|
|
||||||
m_disk[unitno] = disk;
|
|
||||||
|
|
||||||
// If the controllder doesn't already exist, create it.
|
|
||||||
if (m_ctrl[id] == nullptr){
|
|
||||||
// We need to create a new controller
|
|
||||||
if(disk->IsSASI()){
|
|
||||||
m_ctrl[id] = new SASIDEV();
|
|
||||||
}else{
|
|
||||||
m_ctrl[id] = new SCSIDEV();
|
|
||||||
}
|
|
||||||
m_ctrl[id]->Connect(id, m_bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the disk to the controller
|
|
||||||
m_ctrl[id]->SetUnit(unit_num, disk);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL Rascsi_Manager::DetachDevicePrivate(FILE *fp, int id, int unit_num)
|
|
||||||
{
|
|
||||||
int unitno = (id * UnitNum) + unit_num;
|
|
||||||
|
|
||||||
// Disconnect it from the controller
|
|
||||||
if (m_ctrl[id]) {
|
|
||||||
m_ctrl[id]->SetUnit(unit_num, NULL);
|
|
||||||
// Free the Unit
|
|
||||||
delete m_disk[unitno];
|
|
||||||
m_disk[unitno] = nullptr;
|
|
||||||
}else{
|
|
||||||
fprintf(fp, "Warning: A controller was not connected to the drive at id %d un %d\n",id, unit_num);
|
|
||||||
fprintf(fp, "This is some sort of internal error, since you can't have a device without a controller.\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no longer any units connected to this controller, delete it
|
|
||||||
if(!m_ctrl[id]->HasUnit()){
|
|
||||||
delete m_ctrl[id];
|
|
||||||
m_ctrl[id] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Disk* Rascsi_Manager::GetDevice(FILE *fp, int id, int unit_num)
|
|
||||||
{
|
|
||||||
int unitno = (id * UnitNum) + unit_num;
|
|
||||||
return m_disk[unitno];
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// GetCurrentDeviceMode
|
|
||||||
//
|
|
||||||
// Loop through all of the controllers and check if we have SCSI or SASI
|
|
||||||
// controllers already created. (Note: We can't have a mix of them)
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
Rascsi_Device_Mode_e Rascsi_Manager::GetCurrentDeviceMode(){
|
|
||||||
|
|
||||||
Rascsi_Device_Mode_e mode = rascsi_device_unknown_mode;
|
|
||||||
for(int i =0; i < CtrlMax; i++){
|
|
||||||
if(m_ctrl[i] != nullptr){
|
|
||||||
if(m_ctrl[i]->IsSASI()){
|
|
||||||
if(mode == rascsi_device_unknown_mode){
|
|
||||||
mode = rascsi_device_sasi_mode;
|
|
||||||
}else if(mode == rascsi_device_scsi_mode){
|
|
||||||
mode = rascsi_device_invalid_mode;
|
|
||||||
printf("Error: Mix of SCSI and SASI devices. This isn't allowed. Device %d was SASI, but expecting SCSI\n", i);
|
|
||||||
}
|
|
||||||
}else { // This is SCSI
|
|
||||||
if(mode == rascsi_device_unknown_mode){
|
|
||||||
mode = rascsi_device_scsi_mode;
|
|
||||||
}else if(mode == rascsi_device_sasi_mode){
|
|
||||||
mode = rascsi_device_invalid_mode;
|
|
||||||
printf("Error: Mix of SCSI and SASI devices. This isn't allowed. Device %d was SCSI, but expecting SASI\n", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// 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_initialized != FALSE){
|
|
||||||
printf("Can not initialize Rascsi_Manager twice!!!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
m_initialized = TRUE;
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
m_running = TRUE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BOOL Rascsi_Manager::Step()
|
|
||||||
{
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the bus
|
|
||||||
m_bus->Aquire();
|
|
||||||
#else
|
|
||||||
m_bus->Aquire();
|
|
||||||
if (!m_bus->GetSEL()) {
|
|
||||||
#if !defined(BAREMETAL)
|
|
||||||
usleep(0);
|
|
||||||
#endif // !BAREMETAL
|
|
||||||
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()) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_locked.lock();
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Rascsi_Manager::Stop(){
|
|
||||||
m_running = FALSE;
|
|
||||||
}
|
|
||||||
BOOL Rascsi_Manager::IsRunning(){
|
|
||||||
return (m_running == TRUE);
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// 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>
|
|
||||||
|
|
||||||
enum Rascsi_Device_Mode_e{
|
|
||||||
rascsi_device_unknown_mode,
|
|
||||||
rascsi_device_sasi_mode,
|
|
||||||
rascsi_device_scsi_mode,
|
|
||||||
rascsi_device_invalid_mode,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Rascsi_Manager{
|
|
||||||
public:
|
|
||||||
static Rascsi_Manager* GetInstance();
|
|
||||||
static void MapControler(FILE *fp, Disk **map);
|
|
||||||
|
|
||||||
static void Stop();
|
|
||||||
static BOOL IsRunning();
|
|
||||||
|
|
||||||
static BOOL AttachDevice(FILE *fp, Disk *disk, int id, int ui);
|
|
||||||
static BOOL DetachDevice(FILE *fp, int id, int ui);
|
|
||||||
static Disk* GetDevice(FILE *fp, int id, int ui);
|
|
||||||
static void ListDevice(FILE *fp);
|
|
||||||
static BOOL Init();
|
|
||||||
static void Close();
|
|
||||||
static void Reset();
|
|
||||||
static BOOL Step();
|
|
||||||
static Rascsi_Device_Mode_e GetCurrentDeviceMode();
|
|
||||||
|
|
||||||
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 BOOL m_active;
|
|
||||||
static BOOL m_running;
|
|
||||||
static BOOL m_initialized;
|
|
||||||
|
|
||||||
static BOOL AttachDevicePrivate(FILE *fp, Disk *disk, int id, int ui);
|
|
||||||
static BOOL DetachDevicePrivate(FILE *fp, int id, int ui);
|
|
||||||
|
|
||||||
// Any PUBLIC functions should lock this before accessing the m_ctrl
|
|
||||||
// m_disk or m_bus data structures. The Public functions could be
|
|
||||||
// called from a different thread.
|
|
||||||
static std::timed_mutex m_locked;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user