progress
This commit is contained in:
@ -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)
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
// }
|
||||
// }
|
@ -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();
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// `bytes` in `#[bitfield(bytes = 6)]` causes a warning
|
||||
#![allow(redundant_semicolons)]
|
||||
|
||||
pub mod inquiry;
|
@ -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,
|
||||
|
Reference in New Issue
Block a user