scsi improvements

This commit is contained in:
2025-11-05 14:15:20 -07:00
parent 8290ec40a7
commit 5cbee3715f
4 changed files with 76 additions and 52 deletions

View File

@@ -42,7 +42,7 @@ use abi_sys::EntryFn;
use bumpalo::Bump; use bumpalo::Bump;
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use embassy_executor::{Executor, Spawner}; use embassy_executor::{Executor, Spawner};
use embassy_futures::{join::join, select::select}; use embassy_futures::select::select;
use embassy_rp::{ use embassy_rp::{
Peri, Peri,
gpio::{Input, Level, Output, Pull}, gpio::{Input, Level, Output, Pull},

View File

@@ -1,6 +1,6 @@
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use embassy_futures::yield_now;
use embassy_sync::lazy_lock::LazyLock; use embassy_sync::lazy_lock::LazyLock;
use embassy_time::Timer;
use embassy_usb::Builder; use embassy_usb::Builder;
use embassy_usb::driver::{Driver, EndpointIn, EndpointOut}; use embassy_usb::driver::{Driver, EndpointIn, EndpointOut};
use embedded_sdmmc::{Block, BlockIdx}; use embedded_sdmmc::{Block, BlockIdx};
@@ -18,21 +18,24 @@ const BULK_ENDPOINT_PACKET_SIZE: usize = 64;
// NOT safe to disable usb, or acquire sdcard // NOT safe to disable usb, or acquire sdcard
pub static SCSI_BUSY: AtomicBool = AtomicBool::new(false); pub static SCSI_BUSY: AtomicBool = AtomicBool::new(false);
// start no more transfers, usb is trying to stop
pub static SCSI_HALT: AtomicBool = AtomicBool::new(false);
// number of blocks to read from sd at once // number of blocks to read from sd at once
// higher is better, but is larger. Size is BLOCKS * 512 bytes // higher is better, but is larger. Size is BLOCKS * 512 bytes
const BLOCKS: usize = 1; const BLOCKS: usize = 5;
static mut BLOCK_BUF: LazyLock<[Block; BLOCKS]> = static mut BLOCK_BUF: LazyLock<[Block; BLOCKS]> =
LazyLock::new(|| core::array::from_fn(|_| Block::new())); LazyLock::new(|| core::array::from_fn(|_| Block::new()));
pub struct MassStorageClass<'d, D: Driver<'d>> { pub struct MassStorageClass<'d, D: Driver<'d>> {
temp_sd: Option<SdCard>, // temporary owns sdcard when scsi is running temp_sd: Option<SdCard>, // temporary owns sdcard when scsi is running
pending_eject: bool, pub pending_eject: bool,
bulk_out: D::EndpointOut, bulk_out: D::EndpointOut,
bulk_in: D::EndpointIn, bulk_in: D::EndpointIn,
} }
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> { impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
pub fn new(builder: &mut Builder<'d, D>, temp_sd: Option<SdCard>) -> Self { pub fn new(builder: &mut Builder<'d, D>) -> Self {
let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class
let mut interface = function.interface(); let mut interface = function.interface();
let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None); let mut alt = interface.alt_setting(0x08, SUBCLASS_SCSI, 0x50, None);
@@ -41,7 +44,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
let bulk_in = alt.endpoint_bulk_in(None, BULK_ENDPOINT_PACKET_SIZE as u16); let bulk_in = alt.endpoint_bulk_in(None, BULK_ENDPOINT_PACKET_SIZE as u16);
Self { Self {
temp_sd, temp_sd: None,
pending_eject: false, pending_eject: false,
bulk_out, bulk_out,
bulk_in, bulk_in,
@@ -61,18 +64,31 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
} }
pub async fn return_sdcard(&mut self) { pub async fn return_sdcard(&mut self) {
if self.temp_sd.is_some() { if let Some(card) = self.temp_sd.take() {
let mut guard = SDCARD.get().lock().await; let mut guard = SDCARD.get().lock().await;
guard.replace(self.temp_sd.take().unwrap()).unwrap(); *guard = Some(card);
} }
} }
pub async fn poll(&mut self) { pub async fn poll(&mut self) {
loop { loop {
if SCSI_HALT.load(Ordering::Acquire) {
break;
}
if self.pending_eject {
break;
}
self.handle_cbw().await; self.handle_cbw().await;
Timer::after_millis(10).await; if self.pending_eject {
break;
}
yield_now().await;
} }
stop_usb();
} }
async fn handle_cbw(&mut self) { async fn handle_cbw(&mut self) {
@@ -90,12 +106,6 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
} }
SCSI_BUSY.store(false, Ordering::Release); SCSI_BUSY.store(false, Ordering::Release);
if self.pending_eject {
if let ScsiCommand::Write { lba: _, len: _ } = command {
stop_usb();
}
}
} }
} }
} }

View File

@@ -56,32 +56,43 @@ async fn input_handler() {
if let KeyState::Pressed = event.state { if let KeyState::Pressed = event.state {
match event.key { match event.key {
KeyCode::Up => { KeyCode::Up => {
let mut selections = SELECTIONS.lock().await; if !USB_ACTIVE.load(Ordering::Acquire) {
selections.up(); let mut selections = SELECTIONS.lock().await;
selections.up();
}
} }
KeyCode::Down => { KeyCode::Down => {
let mut selections = SELECTIONS.lock().await; if !USB_ACTIVE.load(Ordering::Acquire) {
selections.down(); let mut selections = SELECTIONS.lock().await;
selections.down();
}
} }
KeyCode::F1 => { KeyCode::F1 => {
match USB_ACTIVE.load(Ordering::Acquire) { match USB_ACTIVE.load(Ordering::Acquire) {
true => stop_usb(), true => {
stop_usb();
// wait for sd card to be put back and then reload selections
while USB_ACTIVE.load(Ordering::Acquire) {
Timer::after_millis(100).await
}
update_selections().await
}
false => start_usb(), false => start_usb(),
}; };
update_selections().await;
} }
KeyCode::Enter | KeyCode::Right => { KeyCode::Enter | KeyCode::Right => {
stop_usb(); if !USB_ACTIVE.load(Ordering::Acquire) {
let selections = SELECTIONS.lock().await; let selections = SELECTIONS.lock().await;
let selection = let selection =
selections.selections[selections.current_selection as usize].clone(); selections.selections[selections.current_selection as usize].clone();
let entry = unsafe { let entry = unsafe {
load_binary(&selection.short_name) load_binary(&selection.short_name)
.await .await
.expect("unable to load binary") .expect("unable to load binary")
}; };
BINARY_CH.send(entry).await; BINARY_CH.send(entry).await;
}
} }
_ => (), _ => (),
} }

View File

@@ -1,9 +1,5 @@
use crate::scsi::{MassStorageClass, SCSI_BUSY, SCSI_HALT};
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use crate::{
scsi::{MassStorageClass, SCSI_BUSY},
storage::SdCard,
};
use embassy_futures::{join::join, select::select}; use embassy_futures::{join::join, select::select};
use embassy_rp::{peripherals::USB, usb::Driver}; use embassy_rp::{peripherals::USB, usb::Driver};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel}; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel};
@@ -39,32 +35,41 @@ pub async fn usb_handler(driver: Driver<'static, USB>) {
&mut control_buf, &mut control_buf,
); );
let temp_sd: Option<SdCard> = None; let mut scsi = MassStorageClass::new(&mut builder);
let mut scsi = MassStorageClass::new(&mut builder, temp_sd);
let mut usb = builder.build(); let mut usb = builder.build();
loop { loop {
START_USB.receiver().receive().await; START_USB.receiver().receive().await;
#[cfg(feature = "defmt")] USB_ACTIVE.store(true, Ordering::Release);
SCSI_HALT.store(false, Ordering::Release);
scsi.take_sdcard().await; scsi.take_sdcard().await;
defmt::info!("starting usb"); scsi.pending_eject = false;
// waits for cancellation signal, and then waits for
// transfers to stop before dropping usb future
select( select(
// waits for cancellation signal, and then waits for
// transfers to stop before dropping usb future
async { async {
STOP_USB.receiver().receive().await; STOP_USB.receiver().receive().await;
SCSI_HALT.store(true, Ordering::Release);
while SCSI_BUSY.load(Ordering::Acquire) {
Timer::after_millis(100).await;
}
},
async {
// runs the usb, until cancelled
join(
async {
let _ = usb.remote_wakeup().await;
usb.run().await
},
scsi.poll(),
)
.await;
}, },
// runs the usb, until cancelled
join(usb.run(), scsi.poll()),
) )
.await; .await;
while SCSI_BUSY.load(Ordering::Acquire) {
Timer::after_millis(100).await;
}
#[cfg(feature = "defmt")]
defmt::info!("disabling usb");
scsi.return_sdcard().await;
usb.disable().await; usb.disable().await;
scsi.return_sdcard().await;
USB_ACTIVE.store(false, Ordering::Release); USB_ACTIVE.store(false, Ordering::Release);
} }
} }
@@ -72,11 +77,9 @@ pub async fn usb_handler(driver: Driver<'static, USB>) {
pub fn start_usb() { pub fn start_usb() {
let _ = STOP_USB.receiver().try_receive(); let _ = STOP_USB.receiver().try_receive();
let _ = START_USB.sender().try_send(()); let _ = START_USB.sender().try_send(());
USB_ACTIVE.store(true, Ordering::Release);
} }
pub fn stop_usb() { pub fn stop_usb() {
let _ = START_USB.receiver().try_receive(); let _ = START_USB.receiver().try_receive();
let _ = STOP_USB.sender().try_send(()); let _ = STOP_USB.sender().try_send(());
USB_ACTIVE.store(false, Ordering::Release);
} }