mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Implements READ BUFFER to do, you know, *something*. Plus READ CAPACITY.
The HD SC utility now offers up drive 6 for formatting. That's progress.
This commit is contained in:
parent
6fc5b4e825
commit
87e8dade2f
@ -25,6 +25,28 @@ bool DirectAccessDevice::read(const Target::CommandState &state, Target::Respond
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectAccessDevice::read_capacity(const Target::CommandState &state, Target::Responder &responder) {
|
||||
const auto final_block = device_->get_number_of_blocks() - 1;
|
||||
const auto block_size = device_->get_block_size();
|
||||
std::vector<uint8_t> data = {
|
||||
uint8_t(final_block >> 24),
|
||||
uint8_t(final_block >> 16),
|
||||
uint8_t(final_block >> 8),
|
||||
uint8_t(final_block >> 0),
|
||||
|
||||
uint8_t(block_size >> 24),
|
||||
uint8_t(block_size >> 16),
|
||||
uint8_t(block_size >> 8),
|
||||
uint8_t(block_size >> 0),
|
||||
};
|
||||
|
||||
responder.send_data(std::move(data), [] (const Target::CommandState &state, Target::Responder &responder) {
|
||||
responder.terminate_command(Target::Responder::Status::Good);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Target::Executor::Inquiry DirectAccessDevice::inquiry_values() {
|
||||
return Inquiry("Apple", "ProFile", "1"); // All just guesses.
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ class DirectAccessDevice: public Target::Executor {
|
||||
/* SCSI commands. */
|
||||
bool read(const Target::CommandState &, Target::Responder &);
|
||||
Inquiry inquiry_values();
|
||||
bool read_capacity(const Target::CommandState &, Target::Responder &);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Storage::MassStorage::MassStorageDevice> device_;
|
||||
|
@ -46,7 +46,7 @@ size_t CommandState::allocated_inquiry_bytes() const {
|
||||
}
|
||||
|
||||
CommandState::ModeSense CommandState::mode_sense_specs() const {
|
||||
CommandState::ModeSense specs;
|
||||
ModeSense specs;
|
||||
|
||||
specs.exclude_block_descriptors = (data_[1] & 0x08);
|
||||
specs.page_control_values = ModeSense::PageControlValues(data_[2] >> 5);
|
||||
@ -56,3 +56,15 @@ CommandState::ModeSense CommandState::mode_sense_specs() const {
|
||||
|
||||
return specs;
|
||||
}
|
||||
|
||||
CommandState::ReadBuffer CommandState::read_buffer_specs() const {
|
||||
ReadBuffer specs;
|
||||
|
||||
specs.mode = ReadBuffer::Mode(data_[1]&7);
|
||||
if(specs.mode > ReadBuffer::Mode::Reserved) specs.mode = ReadBuffer::Mode::Reserved;
|
||||
specs.buffer_id = data_[2];
|
||||
specs.buffer_offset = uint32_t((data_[3] << 16) | (data_[4] << 8) | data_[5]);
|
||||
specs.buffer_length = uint32_t((data_[6] << 16) | (data_[7] << 8) | data_[8]);
|
||||
|
||||
return specs;
|
||||
}
|
||||
|
@ -47,6 +47,19 @@ class CommandState {
|
||||
};
|
||||
ModeSense mode_sense_specs() const;
|
||||
|
||||
struct ReadBuffer {
|
||||
enum class Mode {
|
||||
CombinedHeaderAndData = 0,
|
||||
VendorSpecific = 1,
|
||||
Data = 2,
|
||||
Descriptor = 3,
|
||||
Reserved = 4
|
||||
} mode = Mode::CombinedHeaderAndData;
|
||||
uint8_t buffer_id = 0;
|
||||
uint32_t buffer_offset = 0, buffer_length = 0;
|
||||
};
|
||||
ReadBuffer read_buffer_specs() const;
|
||||
|
||||
private:
|
||||
const std::vector<uint8_t> &data_;
|
||||
};
|
||||
@ -137,7 +150,7 @@ struct Executor {
|
||||
bool write_diagnostic(const CommandState &, Responder &) { return false; }
|
||||
|
||||
/// Mode sense: the default implementation will call into the appropriate
|
||||
/// strucutred getter.
|
||||
/// structured getter.
|
||||
bool mode_sense(const CommandState &state, Responder &responder) {
|
||||
const auto specs = state.mode_sense_specs();
|
||||
std::vector<uint8_t> response = {
|
||||
@ -270,6 +283,16 @@ struct Executor {
|
||||
bool search_data_equal(const CommandState &, Responder &) { return false; }
|
||||
bool search_data_high(const CommandState &, Responder &) { return false; }
|
||||
bool search_data_low(const CommandState &, Responder &) { return false; }
|
||||
bool read_buffer(const CommandState &state, Responder &responder) {
|
||||
// Since I have no idea what earthly function READ BUFFER is meant to allow,
|
||||
// the default implementation just returns an empty buffer of the requested size.
|
||||
const auto specs = state.read_buffer_specs();
|
||||
responder.send_data(std::vector<uint8_t>(specs.buffer_length), [] (const Target::CommandState &, Target::Responder &responder) {
|
||||
responder.terminate_command(Target::Responder::Status::Good);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Group 5 commands. */
|
||||
bool set_block_limits(const CommandState &, Responder &) { return false; }
|
||||
|
@ -186,12 +186,12 @@ template <typename Executor> bool Target<Executor>::dispatch_command() {
|
||||
case G0(0x08): return executor_.read(arguments, *this);
|
||||
case G0(0x0a): return executor_.write(arguments, *this);
|
||||
case G0(0x0b): return executor_.seek(arguments, *this);
|
||||
case G0(0x12): return executor_.inquiry(arguments, *this);
|
||||
case G0(0x16): return executor_.reserve_unit(arguments, *this);
|
||||
case G0(0x17): return executor_.release_unit(arguments, *this);
|
||||
case G0(0x1a): return executor_.mode_sense(arguments, *this);
|
||||
case G0(0x1c): return executor_.read_diagnostic(arguments, *this);
|
||||
case G0(0x1d): return executor_.write_diagnostic(arguments, *this);
|
||||
case G0(0x12): return executor_.inquiry(arguments, *this);
|
||||
case G0(0x1a): return executor_.mode_sense(arguments, *this);
|
||||
|
||||
case G1(0x05): return executor_.read_capacity(arguments, *this);
|
||||
case G1(0x08): return executor_.read(arguments, *this);
|
||||
@ -201,6 +201,7 @@ template <typename Executor> bool Target<Executor>::dispatch_command() {
|
||||
case G1(0x11): return executor_.search_data_equal(arguments, *this);
|
||||
case G1(0x10): return executor_.search_data_high(arguments, *this);
|
||||
case G1(0x12): return executor_.search_data_low(arguments, *this);
|
||||
case G1(0x1c): return executor_.read_buffer(arguments, *this);
|
||||
|
||||
case G5(0x09): return executor_.set_block_limits(arguments, *this);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user