This commit is contained in:
chemicstry
2023-01-23 18:03:34 +02:00
parent 2e5a437e59
commit b5b1802a57
11 changed files with 381 additions and 187 deletions

View File

@ -1,12 +1,6 @@
pub mod subclass;
pub mod transport;
use core::marker::PhantomData;
use crate::driver::Driver;
use crate::types::InterfaceNumber;
use crate::Builder;
/// USB Mass Storage Class ID
///
/// Section 4.3 [USB Bulk Only Transport Spec](https://www.usb.org/document-library/mass-storage-bulk-only-10)

View File

@ -8,3 +8,14 @@
// #[skip]
// __: B2,
// }
use crate::packed_struct;
packed_struct! {
pub struct Control<1> {
#[offset = 0, size = 2]
vendor_specific: u8,
#[offset = 5, size = 1]
naca: bool,
}
}

View File

@ -15,3 +15,43 @@
// /// Control byte
// pub control: Control,
// }
use super::control::Control;
use crate::class::msc::subclass::scsi::enums::{PeripheralDeviceType, PeripheralQualifier};
use crate::packed::PackedField;
use crate::packed_struct;
packed_struct! {
pub struct InquiryCommand<6> {
#[offset = 0, size = 8]
op_code: u8,
#[offset = 1*8, size = 1]
enable_vital_product_data: bool,
#[offset = 2*8, size = 8]
page_code: u8,
#[offset = 3*8, size = 16]
allocation_length: u16,
#[offset = 5*8, size = 8]
control: Control<T>,
}
}
impl InquiryCommand<[u8; InquiryCommand::SIZE]> {
pub const OPCODE: u8 = 0x12;
}
// impl<T: AsRef<[u8]>> defmt::Format for InquiryCommand<T> {
// fn format(&self, fmt: defmt::Formatter) {
// fmt.
// }
// }
packed_struct! {
/// Inquiry response can contain many extensions. We support only the minimum required 36 bytes.
pub struct InquiryResponse<36> {
#[offset = 0, size = 5]
peripheral_qualifier: PeripheralQualifier,
#[offset = 5, size = 3]
peripheral_device_type: PeripheralDeviceType,
}
}

View File

@ -1,6 +1,6 @@
use crate::gen_enum;
use crate::packed_enum;
gen_enum! {
packed_enum! {
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum PeripheralQualifier<u8> {
/// A peripheral device having the specified peripheral device type is connected to this logical unit. If the device server is unable to determine whether or not a peripheral device is connected, it also shall use this peripheral qualifier. This peripheral qualifier does not mean that the peripheral device connected to the logical unit is ready for access.
@ -12,7 +12,7 @@ gen_enum! {
}
}
gen_enum! {
packed_enum! {
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum PeripheralDeviceType<u8> {
/// Direct access block device (e.g., magnetic disk)

View File

@ -2,10 +2,9 @@
pub mod block_device;
pub mod commands;
pub mod enums;
pub mod packet;
pub mod responses;
use self::block_device::BlockDevice;
use crate::class::msc::subclass::scsi::commands::inquiry::InquiryCommand;
use crate::class::msc::transport::{self, CommandSetHandler};
pub struct Scsi<B: BlockDevice> {
@ -21,6 +20,15 @@ impl<B: BlockDevice> CommandSetHandler for Scsi<B> {
) -> Result<(), transport::CommandError> {
assert!(lun == 0, "LUNs are not supported");
let op_code = cmd[0];
match op_code {
InquiryCommand::OPCODE => {
let cmd = InquiryCommand::from_bytes(cmd);
// info!("inquiry: {:#?}", cmd);
}
_ => warn!("Unknown opcode: {}", op_code),
}
Ok(())
}

View File

@ -1,151 +0,0 @@
pub trait BitField {
type Output;
fn get(data: &[u8], offset: usize, size: usize) -> Self::Output;
fn set(data: &mut [u8], offset: usize, size: usize, val: Self);
}
impl BitField for u8 {
type Output = u8;
#[inline]
fn get(data: &[u8], offset: usize, size: usize) -> Self::Output {
let byte = offset / 8;
let bit = offset % 8;
let mask = (0xFF >> size) << bit;
(data[byte] & mask) >> bit
}
#[inline]
fn set(data: &mut [u8], offset: usize, size: usize, val: Self) {
let byte = offset / 8;
let bit = offset % 8;
data[byte] = 0;
}
}
#[macro_export]
macro_rules! gen_packet {
(
$(#[$meta:meta])*
$sv:vis struct $name:ident<$size:literal> {
$(
#[offset = $offset:expr, size = $bit_size:expr]
$field:ident: $ty:ty,
)*
}
) => {
$(#[$meta])*
$sv struct $name<T: AsRef<[u8]>> {
data: T
}
impl $name<[u8; $size]> {
const SIZE: usize = $size;
pub fn new() -> Self {
Self {
data: [0u8; Self::SIZE]
}
}
}
impl<T: AsRef<[u8]>> $name<T> {
pub const unsafe fn new_unchecked(data: T) -> Self {
Self { data }
}
pub fn from_bytes(buf: T) -> Option<Self> {
if buf.as_ref().len() < $name::SIZE {
None
} else {
Some(unsafe { Self::new_unchecked(buf) })
}
}
$(
#[inline]
pub fn $field(&self) -> <$ty as crate::class::msc::subclass::scsi::packet::BitField>::Output {
const _: () = core::assert!($offset + $bit_size <= $size * 8, "Field offset is out of range");
<$ty as crate::class::msc::subclass::scsi::packet::BitField>::get(self.data.as_ref(), $offset, $bit_size)
}
)*
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> $name<T> {
$(
paste::paste! {
#[inline]
pub fn [<set_$field>](&mut self, val: $ty) {
<$ty as crate::class::msc::subclass::scsi::packet::BitField>::set(self.data.as_mut(), $offset, $bit_size, val)
}
}
)*
}
}
}
// gen_packet!(pub struct Test<8> {
// #[offset = 8 * 7, size = 3]
// test: u8,
// });
#[macro_export]
macro_rules! gen_enum {
(
$(#[$meta:meta])*
$sv:vis enum $name:ident<$ty:ty> {
$(
$(#[$variant_meta:meta])*
$variant:ident = $variant_val:literal,
)*
}
) => {
$(#[$meta])*
$sv enum $name {
$(
$(#[$variant_meta])*
$variant = $variant_val
),*
}
impl TryFrom<$ty> for $name {
type Error = $ty;
fn try_from(value: $ty) -> Result<Self, Self::Error> {
match value {
$($variant_val => Ok($name::$variant),)*
_ => Err(value)
}
}
}
impl From<$name> for $ty {
fn from(value: $name) -> $ty {
value as $ty
}
}
impl crate::class::msc::subclass::scsi::packet::BitField for $name {
type Output = Result<Self, $ty>;
#[inline]
fn get(data: &[u8], offset: usize, size: usize) -> Self::Output {
let val = <$ty as crate::class::msc::subclass::scsi::packet::BitField>::get(data, offset, size);
Self::try_from(val)
}
#[inline]
fn set(data: &mut [u8], offset: usize, size: usize, val: Self) {
<$ty as crate::class::msc::subclass::scsi::packet::BitField>::set(data, offset, size, val.into());
}
}
};
}
// gen_enum! {
// pub enum Testas<u8> {
// Hello = 0b111,
// Test = 0b1111,
// }
// }

View File

@ -1,17 +0,0 @@
use super::super::enums::PeripheralQualifier;
use crate::class::msc::subclass::scsi::enums::PeripheralDeviceType;
use crate::gen_packet;
gen_packet! {
/// Inquiry response can contain many extensions. We support only the minimum required 36 bytes.
pub struct InquiryResponse<36> {
#[offset = 0, size = 5]
peripheral_qualifier: PeripheralQualifier,
#[offset = 5, size = 3]
peripheral_device_type: PeripheralDeviceType,
}
}
fn test() {
let packet = InquiryResponse::new();
}

View File

@ -1,4 +0,0 @@
// `bytes` in `#[bitfield(bytes = 6)]` causes a warning
#![allow(redundant_semicolons)]
pub mod inquiry;

View File

@ -11,7 +11,6 @@ use super::{CommandError, CommandSetHandler, DataPipeError, DataPipeIn, DataPipe
use crate::class::msc::{MscProtocol, MscSubclass, USB_CLASS_MSC};
use crate::control::{ControlHandler, InResponse, Request, RequestType};
use crate::driver::Driver;
use crate::types::InterfaceNumber;
use crate::Builder;
const REQ_GET_MAX_LUN: u8 = 0xFE;
@ -51,7 +50,6 @@ impl ControlHandler for Control {
}
pub struct BulkOnlyTransport<'d, D: Driver<'d>, C: CommandSetHandler> {
msc_if: InterfaceNumber,
read_ep: D::EndpointOut,
write_ep: D::EndpointIn,
max_packet_size: u16,
@ -77,14 +75,12 @@ impl<'d, D: Driver<'d>, C: CommandSetHandler> BulkOnlyTransport<'d, D, C> {
let mut iface = func.interface();
iface.handler(control);
let msc_if = iface.interface_number();
let mut alt = iface.alt_setting(USB_CLASS_MSC, subclass as _, MscProtocol::BulkOnlyTransport as _);
let read_ep = alt.endpoint_bulk_out(max_packet_size);
let write_ep = alt.endpoint_bulk_in(max_packet_size);
Self {
msc_if,
read_ep,
write_ep,
max_packet_size,