can unmount now

This commit is contained in:
2025-07-29 13:49:58 -06:00
parent 2bddec08e6
commit 0d77321bb3
3 changed files with 47 additions and 16 deletions

View File

@@ -12,8 +12,15 @@ use crate::storage::SdCard;
const BULK_ENDPOINT_PACKET_SIZE: usize = 64;
#[derive(PartialEq, Eq)]
enum State {
Ready,
Ejected,
}
pub struct MassStorageClass<'d, D: Driver<'d>> {
sdcard: SdCard,
state: State,
bulk_out: D::EndpointOut,
bulk_in: D::EndpointIn,
last_sense: Option<ScsiError>,
@@ -32,6 +39,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
bulk_out,
bulk_in,
sdcard,
state: State::Ready,
last_sense: None,
}
}
@@ -42,6 +50,12 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
if let Ok(n) = self.bulk_out.read(&mut cbw_buf).await {
if n == 31 {
if let Some(cbw) = CommandBlockWrapper::parse(&cbw_buf[..n]) {
if self.state == State::Ejected {
self.last_sense = Some(ScsiError::NotReady);
self.send_csw_fail(cbw.dCBWTag).await;
continue;
}
// TODO: validate cbw
if self.handle_command(&cbw.CBWCB).await.is_ok() {
self.send_csw_success(cbw.dCBWTag).await
@@ -213,7 +227,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
ScsiCommand::Read { lba, len } => {
for i in 0..len {
let block_idx = BlockIdx(lba as u32 + i as u32);
self.sdcard.read_blocks(&mut block, block_idx);
self.sdcard.read_blocks(&mut block, block_idx)?;
for chunk in block[0].contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) {
self.bulk_in.write(chunk).await.map_err(|_| ())?;
}
@@ -227,9 +241,9 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
.contents
.chunks_mut(BULK_ENDPOINT_PACKET_SIZE.into())
{
slf.bulk_out.read(chunk).await.map_err(|_| ())?;
self.bulk_out.read(chunk).await.map_err(|_| ())?;
}
self.sdcard.write_blocks(&mut block, block_idx);
self.sdcard.write_blocks(&mut block, block_idx)?;
}
Ok(())
}
@@ -254,6 +268,13 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
.map_err(|_| ())
}
ScsiCommand::PreventAllowMediumRemoval { prevent: _prevent } => Ok(()),
ScsiCommand::StartStopUnit { stop, load_eject } => {
if stop && load_eject {
self.state = State::Ejected;
self.last_sense = Some(ScsiError::NotReady);
}
Ok(())
}
}
}

View File

@@ -2,10 +2,7 @@ use num_enum::TryFromPrimitive;
#[derive(Debug, Clone, Copy)]
pub enum ScsiError {
IllegalRequest { asc: u8, ascq: u8 },
NotReady { asc: u8, ascq: u8 },
MediumError { asc: u8, ascq: u8 },
// Add others as needed
NotReady,
}
/// THE CODE BELOW ORIGINATES FROM: https://github.com/apohrebniak/usbd-storage/blob/master/usbd-storage/src/subclass/scsi.rs
@@ -33,6 +30,7 @@ const WRITE_10: u8 = 0x2A;
const READ_FORMAT_CAPACITIES: u8 = 0x23;
const PREVENT_ALLOW_MEDIUM_REMOVAL: u8 = 0x1E;
const START_STOP_UNIT: u8 = 0x1B;
/// SCSI command
///
@@ -91,6 +89,11 @@ pub enum ScsiCommand {
PreventAllowMediumRemoval {
prevent: bool,
},
StartStopUnit {
stop: bool,
load_eject: bool,
},
}
#[repr(u8)]
@@ -152,6 +155,10 @@ pub fn parse_cb(cb: &[u8]) -> ScsiCommand {
PREVENT_ALLOW_MEDIUM_REMOVAL => ScsiCommand::PreventAllowMediumRemoval {
prevent: (cb[1] & 0b00000001) != 0,
},
START_STOP_UNIT => ScsiCommand::StartStopUnit {
stop: (cb[1] & 0b00000001) != 0,
load_eject: (cb[1] & 0b00000010) == 0,
},
_ => ScsiCommand::Unknown,
}
}

View File

@@ -1,12 +1,11 @@
use embassy_futures::block_on;
use embassy_rp::gpio::{Input, Output};
use embassy_rp::peripherals::SPI0;
use embassy_rp::spi::{Blocking, Spi};
use embassy_time::Delay;
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::{self, Block, BlockIdx};
use embedded_sdmmc::{
BlockCount, BlockDevice, Directory, SdCard as SdmmcSdCard, TimeSource, Timestamp, Volume,
VolumeIdx, VolumeManager,
Block, BlockCount, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource,
Timestamp, Volume, VolumeIdx, VolumeManager, sdcard::Error,
};
pub const MAX_DIRS: usize = 4;
@@ -14,7 +13,7 @@ pub const MAX_FILES: usize = 5;
pub const MAX_VOLUMES: usize = 1;
type Device = ExclusiveDevice<Spi<'static, SPI0, Blocking>, Output<'static>, embassy_time::Delay>;
type SD = SdmmcSdCard<Device, embassy_time::Delay>;
type SD = SdmmcSdCard<Device, Delay>;
type VolMgr = VolumeManager<SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
@@ -83,17 +82,21 @@ impl SdCard {
result
}
pub fn read_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) {
pub fn read_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), ()> {
let mut res: Result<(), Error> = Ok(());
self.volume_mgr.device(|sd| {
sd.read(blocks, start_block_idx);
res = sd.read(blocks, start_block_idx);
DummyTimeSource {}
});
res.map_err(|_| ())
}
pub fn write_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) {
pub fn write_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), ()> {
let mut res: Result<(), Error> = Ok(());
self.volume_mgr.device(|sd| {
sd.write(blocks, start_block_idx);
let res = sd.write(blocks, start_block_idx);
DummyTimeSource {}
});
res.map_err(|_| ())
}
}