47static constexpr uint8_t MT_UNKNOWN = 0x00;
48static constexpr uint8_t MT_2DD_UN = 0x10;
49static constexpr uint8_t MT_2DD = 0x11;
50static constexpr uint8_t MT_2HD_UN = 0x20;
51static constexpr uint8_t MT_2HD_12_98 = 0x22;
52static constexpr uint8_t MT_2HD_12 = 0x23;
53static constexpr uint8_t MT_2HD_144 = 0x24;
54static constexpr uint8_t MT_LS120 = 0x31;
55static constexpr uint8_t MT_NO_DISK = 0x70;
56static constexpr uint8_t MT_DOOR_OPEN = 0x71;
57static constexpr uint8_t MT_FMT_ERROR = 0x72;
59static constexpr std::array<uint8_t, 36> inqData = {
70 'o',
'p',
'e',
'n',
'M',
'S',
'X',
' ',
71 'S',
'C',
'S',
'I',
'2',
' ',
'L',
'S',
72 '-',
'1',
'2',
'0',
'd',
'i',
's',
'k',
77static constexpr std::string_view fds120 =
"IODATA LS-120 COSM 0001";
84 : motherBoard(targetConfig.getMotherBoard())
88 , scsiId(
narrow_cast<uint8_t>(targetConfig.getAttributeValueAsInt(
"id", 0)))
93 while ((*lsInUse)[
id]) {
99 name[2] = char(
'a' +
id);
100 (*lsInUse)[
id] =
true;
119 unsigned id = name[2] -
'a';
120 assert((*lsInUse)[
id]);
121 (*lsInUse)[
id] =
false;
130void SCSILS120::reset()
132 mediaChanged =
false;
138void SCSILS120::busReset()
144void SCSILS120::disconnect()
150bool SCSILS120::isSelected()
156bool SCSILS120::getReady()
158 if (file.
is_open())
return true;
163void SCSILS120::testUnitReady()
171 mediaChanged =
false;
174void SCSILS120::startStopUnit()
190unsigned SCSILS120::inquiry()
193 unsigned length = currentLength;
195 bool fdsMode = (total > 0) && (total <= 2880);
197 if (
length == 0)
return 0;
211 if (!fdsMode) buffer[20] =
'1';
215 if (!fdsMode) buffer[20] =
'3';
223 memset(buffer + 56, 0, 40);
234 filename.resize(20,
' ');
240unsigned SCSILS120::modeSense()
242 uint8_t* pBuffer = buffer;
244 if ((currentLength > 0) && (cdb[2] == 3)) {
246 uint8_t media = MT_UNKNOWN;
247 uint8_t sectors = 64;
250 uint8_t
size = 4 + 24;
251 uint8_t removable = 0xa0;
253 memset(pBuffer + 2, 0, 34);
261 blockLength = 2048 >> 8;
267 blockLength = 2048 >> 8;
279 if (!(cdb[1] & 0x08)) {
281 pBuffer[1] = (total >> 16) & 0xff;
282 pBuffer[2] = (total >> 8) & 0xff;
283 pBuffer[3] = (total >> 0) & 0xff;
284 pBuffer[6] = blockLength & 0xff;
292 pBuffer[ 3] = tracks;
293 pBuffer[11] = sectors;
294 pBuffer[12] = blockLength;
295 pBuffer[20] = removable;
297 buffer[0] =
size - 1;
299 return std::min<unsigned>(currentLength,
size);
305unsigned SCSILS120::requestSense()
307 unsigned length = currentLength;
309 unitAttention =
false;
313 memset(buffer + 1, 0, 17);
318 buffer[ 0] = (tmpKeycode >> 8) & 0xff;
322 buffer[ 2] = (tmpKeycode >> 16) & 0xff;
324 buffer[12] = (tmpKeycode >> 8) & 0xff;
325 buffer[13] = (tmpKeycode >> 0) & 0xff;
331bool SCSILS120::checkReadOnly()
340unsigned SCSILS120::readCapacity()
357bool SCSILS120::checkAddress()
366 if ((currentLength > 0) && (currentSector + currentLength <= total)) {
374unsigned SCSILS120::readSector(
unsigned& blocks)
378 unsigned numSectors =
std::min(currentLength, BUFFER_BLOCK_SIZE);
385 currentSector += numSectors;
386 currentLength -= numSectors;
387 blocks = currentLength;
389 }
catch (FileException&) {
396unsigned SCSILS120::dataIn(
unsigned& blocks)
399 unsigned counter = readSector(blocks);
410unsigned SCSILS120::writeSector(
unsigned& blocks)
414 unsigned numSectors =
std::min(currentLength, BUFFER_BLOCK_SIZE);
420 currentSector += numSectors;
421 currentLength -= numSectors;
423 unsigned tmp =
std::min(currentLength, BUFFER_BLOCK_SIZE);
424 blocks = currentLength - tmp;
427 }
catch (FileException&) {
434unsigned SCSILS120::dataOut(
unsigned& blocks)
437 return writeSector(blocks);
445void SCSILS120::formatUnit()
447 if (getReady() && !checkReadOnly()) {
452 unitAttention =
true;
454 }
catch (FileException&) {
460uint8_t SCSILS120::getStatusCode()
465void SCSILS120::eject()
470 unitAttention =
true;
475void SCSILS120::insert(
const std::string& filename)
477 file = File(filename);
480 unitAttention =
true;
485unsigned SCSILS120::executeCmd(std::span<const uint8_t, 12> cdb_,
SCSI::Phase& phase,
unsigned& blocks)
495 unitAttention =
false;
498 mediaChanged =
false;
517 currentSector = ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
518 currentLength = cdb[4];
526 unsigned counter = inquiry();
533 unsigned counter = requestSense();
540 if (currentLength == 0) {
543 if (checkAddress()) {
544 unsigned counter = readSector(blocks);
554 if (currentLength == 0) {
557 if (checkAddress() && !checkReadOnly()) {
559 unsigned tmp =
std::min(currentLength, BUFFER_BLOCK_SIZE);
560 blocks = currentLength - tmp;
571 (void)checkAddress();
575 unsigned counter = modeSense();
603 if (checkAddress()) {
604 unsigned counter = readSector(blocks);
613 if (checkAddress() && !checkReadOnly()) {
614 unsigned tmp =
std::min(currentLength, BUFFER_BLOCK_SIZE);
615 blocks = currentLength - tmp;
623 unsigned counter = readCapacity();
632 (void)checkAddress();
642unsigned SCSILS120::executingCmd(
SCSI::Phase& phase,
unsigned& blocks)
649uint8_t SCSILS120::msgIn()
651 uint8_t result = message;
665int SCSILS120::msgOut(uint8_t value)
689 return ((value >= 0x04) && (value <= 0x11)) ? 3 : 1;
692size_t SCSILS120::getNbSectorsImpl()
const
697bool SCSILS120::isWriteProtectedImpl()
const
702Sha1Sum SCSILS120::getSha1SumImpl(FilePool& filePool)
707 return filePool.getSha1Sum(file);
710void SCSILS120::readSectorsImpl(
711 std::span<SectorBuffer> buffers,
size_t startSector)
713 file.
seek(startSector *
sizeof(SectorBuffer));
717void SCSILS120::writeSectorImpl(
size_t sector,
const SectorBuffer& buf)
719 file.
seek(
sizeof(buf) * sector);
723SectorAccessibleDisk* SCSILS120::getSectorAccessibleDisk()
728std::string_view SCSILS120::getContainerName()
const
733bool SCSILS120::diskChanged()
738int SCSILS120::insertDisk(
const std::string& filename)
743 }
catch (MSXException&) {
755 scheduler_, ls_.name)
763 if (tokens.size() == 1) {
764 auto& file = ls.file;
766 file.is_open() ? file.getURL() : std::string{});
768 }
else if ((tokens.size() == 2) && (tokens[1] ==
one_of(
"eject",
"-eject"))) {
771 if (tokens[1] ==
"-eject") {
772 result =
"Warning: use of '-eject' is deprecated, "
773 "instead use the 'eject' subcommand";
775 }
else if ((tokens.size() == 2) ||
776 ((tokens.size() == 3) && (tokens[1] ==
"insert"))) {
778 if (tokens[1] ==
"insert") {
779 if (tokens.size() > 2) {
783 "Missing argument to insert subcommand");
800 ls.name,
" : display the disk image for this LS-120 drive\n",
801 ls.name,
" eject : eject the disk image from this LS-120 drive\n",
802 ls.name,
" insert <filename> : change the disk image for this LS-120 drive\n",
803 ls.name,
" <filename> : change the disk image for this LS-120 drive\n");
808 using namespace std::literals;
809 static constexpr std::array extra = {
"eject"sv,
"insert"sv};
814template<
typename Archive>
817 std::string filename = file.
is_open() ? file.
getURL() : std::string{};
818 ar.serialize(
"filename", filename);
819 if constexpr (Archive::IS_LOADER) {
821 if (filename.empty()) {
828 ar.serialize(
"keycode", keycode,
829 "currentSector", currentSector,
830 "currentLength", currentLength,
831 "unitAttention", unitAttention,
832 "mediaChanged", mediaChanged,
835 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
void getMediaInfo(TclObject &result) override
This method gets called when information is required on the media inserted in the media slot of the p...
SCSILS120(const SCSILS120 &)=delete
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)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
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:
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
FileContext userFileContext(string_view savePath)
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)
std::string strCat(Ts &&...ts)