50static constexpr uint8_t MT_UNKNOWN = 0x00;
51static constexpr uint8_t MT_2DD_UN = 0x10;
52static constexpr uint8_t MT_2DD = 0x11;
53static constexpr uint8_t MT_2HD_UN = 0x20;
54static constexpr uint8_t MT_2HD_12_98 = 0x22;
55static constexpr uint8_t MT_2HD_12 = 0x23;
56static constexpr uint8_t MT_2HD_144 = 0x24;
57static constexpr uint8_t MT_LS120 = 0x31;
58static constexpr uint8_t MT_NO_DISK = 0x70;
59static constexpr uint8_t MT_DOOR_OPEN = 0x71;
60static constexpr uint8_t MT_FMT_ERROR = 0x72;
62static constexpr std::array<uint8_t, 36> inqData = {
73 'o',
'p',
'e',
'n',
'M',
'S',
'X',
' ',
74 'S',
'C',
'S',
'I',
'2',
' ',
'L',
'S',
75 '-',
'1',
'2',
'0',
'd',
'i',
's',
'k',
80static constexpr std::string_view fds120 =
"IODATA LS-120 COSM 0001";
87 : motherBoard(targetConfig.getMotherBoard())
91 , scsiId(
narrow_cast<uint8_t>(targetConfig.getAttributeValueAsInt(
"id", 0)))
96 while ((*lsInUse)[
id]) {
102 name[2] = char(
'a' +
id);
103 (*lsInUse)[
id] =
true;
122 unsigned id = name[2] -
'a';
123 assert((*lsInUse)[
id]);
124 (*lsInUse)[
id] =
false;
133void SCSILS120::reset()
135 mediaChanged =
false;
141void SCSILS120::busReset()
147void SCSILS120::disconnect()
153bool SCSILS120::isSelected()
159bool SCSILS120::getReady()
161 if (file.
is_open())
return true;
166void SCSILS120::testUnitReady()
174 mediaChanged =
false;
177void SCSILS120::startStopUnit()
193unsigned SCSILS120::inquiry()
196 unsigned length = currentLength;
198 bool fdsMode = (total > 0) && (total <= 2880);
200 if (length == 0)
return 0;
214 if (!fdsMode) buffer[20] =
'1';
218 if (!fdsMode) buffer[20] =
'3';
223 length = std::min(length, 96u);
226 memset(buffer + 56, 0, 40);
232 length = std::min(length, 56u);
237 filename.resize(20,
' ');
243unsigned SCSILS120::modeSense()
245 uint8_t* pBuffer = buffer;
247 if ((currentLength > 0) && (cdb[2] == 3)) {
249 uint8_t media = MT_UNKNOWN;
250 uint8_t sectors = 64;
253 uint8_t
size = 4 + 24;
254 uint8_t removable = 0xa0;
256 memset(pBuffer + 2, 0, 34);
264 blockLength = 2048 >> 8;
270 blockLength = 2048 >> 8;
282 if (!(cdb[1] & 0x08)) {
284 pBuffer[1] = (total >> 16) & 0xff;
285 pBuffer[2] = (total >> 8) & 0xff;
286 pBuffer[3] = (total >> 0) & 0xff;
287 pBuffer[6] = blockLength & 0xff;
295 pBuffer[ 3] = tracks;
296 pBuffer[11] = sectors;
297 pBuffer[12] = blockLength;
298 pBuffer[20] = removable;
300 buffer[0] =
size - 1;
302 return std::min<unsigned>(currentLength, size);
308unsigned SCSILS120::requestSense()
310 unsigned length = currentLength;
312 unitAttention =
false;
316 memset(buffer + 1, 0, 17);
321 buffer[ 0] = (tmpKeycode >> 8) & 0xff;
325 buffer[ 2] = (tmpKeycode >> 16) & 0xff;
327 buffer[12] = (tmpKeycode >> 8) & 0xff;
328 buffer[13] = (tmpKeycode >> 0) & 0xff;
329 length = std::min(length, 18u);
334bool SCSILS120::checkReadOnly()
343unsigned SCSILS120::readCapacity()
360bool SCSILS120::checkAddress()
369 if ((currentLength > 0) && (currentSector + currentLength <= total)) {
377unsigned SCSILS120::readSector(
unsigned& blocks)
381 unsigned numSectors = std::min(currentLength, BUFFER_BLOCK_SIZE);
388 currentSector += numSectors;
389 currentLength -= numSectors;
390 blocks = currentLength;
392 }
catch (FileException&) {
399unsigned SCSILS120::dataIn(
unsigned& blocks)
402 unsigned counter = readSector(blocks);
413unsigned SCSILS120::writeSector(
unsigned& blocks)
417 unsigned numSectors = std::min(currentLength, BUFFER_BLOCK_SIZE);
423 currentSector += numSectors;
424 currentLength -= numSectors;
426 unsigned tmp = std::min(currentLength, BUFFER_BLOCK_SIZE);
427 blocks = currentLength - tmp;
430 }
catch (FileException&) {
437unsigned SCSILS120::dataOut(
unsigned& blocks)
440 return writeSector(blocks);
448void SCSILS120::formatUnit()
450 if (getReady() && !checkReadOnly()) {
455 unitAttention =
true;
457 }
catch (FileException&) {
463uint8_t SCSILS120::getStatusCode()
468void SCSILS120::eject()
473 unitAttention =
true;
478void SCSILS120::insert(
const std::string& filename)
480 file = File(filename);
483 unitAttention =
true;
488unsigned SCSILS120::executeCmd(std::span<const uint8_t, 12> cdb_,
SCSI::Phase& phase,
unsigned& blocks)
500 unitAttention =
false;
503 mediaChanged =
false;
522 currentSector = ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
523 currentLength = cdb[4];
531 unsigned counter = inquiry();
538 unsigned counter = requestSense();
545 if (currentLength == 0) {
548 if (checkAddress()) {
549 unsigned counter = readSector(blocks);
559 if (currentLength == 0) {
562 if (checkAddress() && !checkReadOnly()) {
564 unsigned tmp = std::min(currentLength, BUFFER_BLOCK_SIZE);
565 blocks = currentLength - tmp;
576 (void)checkAddress();
580 unsigned counter = modeSense();
608 if (checkAddress()) {
609 unsigned counter = readSector(blocks);
618 if (checkAddress() && !checkReadOnly()) {
619 unsigned tmp = std::min(currentLength, BUFFER_BLOCK_SIZE);
620 blocks = currentLength - tmp;
628 unsigned counter = readCapacity();
637 (void)checkAddress();
647unsigned SCSILS120::executingCmd(
SCSI::Phase& phase,
unsigned& blocks)
654uint8_t SCSILS120::msgIn()
656 uint8_t result = message;
670int SCSILS120::msgOut(uint8_t value)
694 return ((value >= 0x04) && (value <= 0x11)) ? 3 : 1;
697size_t SCSILS120::getNbSectorsImpl()
const
702bool SCSILS120::isWriteProtectedImpl()
const
707Sha1Sum SCSILS120::getSha1SumImpl(FilePool& filePool)
712 return filePool.getSha1Sum(file);
715void SCSILS120::readSectorsImpl(
716 std::span<SectorBuffer> buffers,
size_t startSector)
718 file.
seek(startSector *
sizeof(SectorBuffer));
722void SCSILS120::writeSectorImpl(
size_t sector,
const SectorBuffer& buf)
724 file.
seek(
sizeof(buf) * sector);
728SectorAccessibleDisk* SCSILS120::getSectorAccessibleDisk()
733std::string_view SCSILS120::getContainerName()
const
738bool SCSILS120::diskChanged()
743int SCSILS120::insertDisk(
const std::string& filename)
748 }
catch (MSXException&) {
760 scheduler_, ls_.name)
768 if (tokens.size() == 1) {
769 const auto& file = ls.file;
771 file.is_open() ? file.getURL() : std::string{});
773 }
else if ((tokens.size() == 2) && (tokens[1] ==
one_of(
"eject",
"-eject"))) {
776 if (tokens[1] ==
"-eject") {
777 result =
"Warning: use of '-eject' is deprecated, "
778 "instead use the 'eject' subcommand";
780 }
else if ((tokens.size() == 2) ||
781 ((tokens.size() == 3) && (tokens[1] ==
"insert"))) {
783 if (tokens[1] ==
"insert") {
784 if (tokens.size() > 2) {
788 "Missing argument to insert subcommand");
805 ls.name,
" : display the disk image for this LS-120 drive\n",
806 ls.name,
" eject : eject the disk image from this LS-120 drive\n",
807 ls.name,
" insert <filename> : change the disk image for this LS-120 drive\n",
808 ls.name,
" <filename> : change the disk image for this LS-120 drive\n");
813 using namespace std::literals;
814 static constexpr std::array extra = {
"eject"sv,
"insert"sv};
819template<
typename Archive>
822 std::string filename = file.
is_open() ? file.
getURL() : std::string{};
823 ar.serialize(
"filename", filename);
824 if constexpr (Archive::IS_LOADER) {
826 if (filename.empty()) {
833 ar.serialize(
"keycode", keycode,
834 "currentSector", currentSector,
835 "currentLength", currentLength,
836 "unitAttention", unitAttention,
837 "mediaChanged", mediaChanged,
840 ar.serialize_blob(
"cdb", cdb);
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
void close()
Close the current file.
void seek(size_t pos)
Move read/write pointer to the specified position.
bool isReadOnly() const
Check if this file is readonly.
void read(std::span< uint8_t > buffer)
Read from file.
void write(std::span< const uint8_t > buffer)
Write to file.
bool is_open() const
Return true iff this file handle refers to an open file.
const std::string & getURL() const
Returns the URL of this file object.
void execute(std::span< const TclObject > tokens, TclObject &result, EmuTime::param time) override
This is like the execute() method of the Command class, it only has an extra time parameter.
void tabCompletion(std::vector< std::string > &tokens) const override
Attempt tab completion for this command.
LSXCommand(CommandController &commandController, StateChangeDistributor &stateChangeDistributor, Scheduler &scheduler, SCSILS120 &ls)
std::string help(std::span< const TclObject > tokens) const override
Print help for this command.
void setLed(Led led, bool status)
void update(UpdateType type, std::string_view name, std::string_view value) override
std::shared_ptr< T > getSharedStuff(std::string_view name, Args &&...args)
Some MSX device parts are shared between several MSX devices (e.g.
Scheduler & getScheduler()
StateChangeDistributor & getStateChangeDistributor()
void registerMediaInfo(std::string_view name, MediaInfoProvider &provider)
Register and unregister providers of media info, for the media info topic.
CommandController & getCommandController()
void unregisterMediaInfo(MediaInfoProvider &provider)
MSXCliComm & getMSXCliComm()
LedStatus & getLedStatus()
Commands that directly influence the MSX state should send and events so that they can be recorded by...
static constexpr unsigned BIT_SCSI3
static constexpr unsigned BUFFER_SIZE
static constexpr unsigned MODE_MEGASCSI
static constexpr unsigned MODE_NOVAXIS
static constexpr unsigned BIT_SCSI2
static constexpr unsigned MODE_UNITATTENTION
SCSILS120(const DeviceConfig &targetConfig, AlignedBuffer &buf, unsigned mode)
void getMediaInfo(TclObject &result) override
This method gets called when information is required on the media inserted in the media slot of the p...
void serialize(Archive &ar, unsigned version)
virtual Sha1Sum getSha1SumImpl(FilePool &filePool)
static constexpr size_t SECTOR_SIZE
size_t getNbSectors() const
void addListElement(const T &t)
void addDictKeyValue(const Key &key, const Value &value)
ALWAYS_INLINE uint16_t read_UA_B16(const void *p)
ALWAYS_INLINE uint32_t read_UA_B32(const void *p)
void writeB32(void *p, uint32_t x)
T length(const vecN< N, T > &x)
string_view getFilename(string_view path)
Returns the file portion of a path name.
constexpr uint8_t MSG_NO_OPERATION
constexpr uint32_t SENSE_POWER_ON
constexpr uint8_t OP_RESERVE_UNIT
constexpr uint8_t ST_GOOD
constexpr uint32_t SENSE_WRITE_PROTECT
constexpr uint32_t SENSE_INVALID_COMMAND_CODE
constexpr uint8_t OP_MODE_SENSE
constexpr uint8_t OP_READ_CAPACITY
constexpr uint8_t ST_CHECK_CONDITION
constexpr uint32_t SENSE_UNRECOVERED_READ_ERROR
constexpr uint32_t SENSE_NO_SENSE
constexpr uint8_t OP_TEST_UNIT_READY
constexpr uint8_t OP_SEEK6
constexpr uint8_t OP_READ6
constexpr uint32_t SENSE_MEDIUM_NOT_PRESENT
constexpr uint8_t MSG_ABORT
constexpr uint8_t OP_REZERO_UNIT
constexpr uint32_t SENSE_WRITE_FAULT
constexpr uint32_t SENSE_ILLEGAL_BLOCK_ADDRESS
constexpr uint8_t OP_WRITE10
constexpr uint8_t MSG_BUS_DEVICE_RESET
constexpr uint8_t OP_WRITE6
constexpr uint8_t OP_INQUIRY
constexpr uint8_t OP_REASSIGN_BLOCKS
constexpr uint8_t OP_SEND_DIAGNOSTIC
constexpr uint8_t MSG_INITIATOR_DETECT_ERROR
constexpr uint32_t SENSE_INVALID_LUN
constexpr uint32_t SENSE_INITIATOR_DETECTED_ERR
constexpr uint8_t OP_FORMAT_UNIT
constexpr uint8_t OP_START_STOP_UNIT
constexpr uint8_t MSG_PARITY_ERROR
constexpr uint8_t OP_READ10
constexpr uint8_t OP_GROUP1
constexpr uint8_t OP_SEEK10
constexpr uint8_t OP_REQUEST_SENSE
constexpr uint8_t MSG_REJECT
constexpr uint8_t DT_DirectAccess
constexpr uint8_t OP_RELEASE_UNIT
This file implemented 3 utility functions:
const FileContext & userFileContext()
constexpr auto copy(InputRange &&range, OutputIter out)
size_t size(std::string_view utf8)
constexpr To narrow_cast(From &&from) noexcept
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
TemporaryString tmpStrCat(Ts &&... ts)