mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
can unmount now
This commit is contained in:
@@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user