re-organize the USB subsystem into modules

This commit is contained in:
bunnie 2024-10-18 14:45:15 +08:00
parent e4f5c32ff3
commit a6e7459cdd
5 changed files with 1202 additions and 1159 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,438 @@
use core::convert::TryFrom;
use core::sync::atomic::{AtomicPtr, Ordering};
use cramium_hal::usb::compat::AtomicCsr;
use cramium_hal::usb::driver::CorigineUsb;
use cramium_hal::usb::driver::*;
use cramium_hal::usb::utra::*;
use super::*;
pub(crate) static mut USB: Option<CorigineUsb> = None;
// todo: figure out how to make this less gross
pub(crate) static mut UMS_STATE: UmsState = UmsState::Idle;
pub fn init_usb() {
let mut usb = unsafe {
cramium_hal::usb::driver::CorigineUsb::new(
0,
0,
cramium_hal::board::CRG_UDC_MEMBASE,
AtomicCsr::new(cramium_hal::usb::utra::CORIGINE_USB_BASE as *mut u32),
AtomicCsr::new(utralib::utra::irqarray1::HW_IRQARRAY1_BASE as *mut u32),
)
};
usb.assign_handler(handle_event);
// initialize the "disk" area
let disk = unsafe { core::slice::from_raw_parts_mut(RAMDISK_ADDRESS as *mut u8, RAMDISK_LEN) };
disk.fill(0);
disk[..MBR_TEMPLATE.len()].copy_from_slice(&MBR_TEMPLATE);
//set block size
disk[0xb..0xd].copy_from_slice(&SECTOR_SIZE.to_le_bytes());
//set storage size
disk[0x20..0x24].copy_from_slice(&(RAMDISK_LEN as u32).to_le_bytes());
// install the interrupt handler
// setup the stack & controller
irq_setup();
enable_irq(utralib::utra::irqarray1::IRQARRAY1_IRQ);
// for testing
// enable_irq(utralib::utra::irqarray19::IRQARRAY19_IRQ);
// let mut irqarray19 = utralib::CSR::new(utralib::utra::irqarray19::HW_IRQARRAY19_BASE as *mut u32);
// irqarray19.wo(utralib::utra::irqarray19::EV_ENABLE, 0x80);
unsafe {
USB = Some(usb);
}
}
pub unsafe fn test_usb() {
if let Some(ref mut usb_ref) = USB {
let usb = &mut *core::ptr::addr_of_mut!(*usb_ref);
usb.reset();
let mut poweron = 0;
loop {
usb.udc_handle_interrupt();
if usb.pp() {
poweron += 1; // .pp() is a sham. MPW has no way to tell if power is applied. This needs to be fixed for NTO.
}
delay(100);
if poweron >= 4 {
break;
}
}
usb.reset();
usb.init();
usb.start();
usb.update_current_speed();
crate::println!("hw started...");
/*
let mut vbus_on = false;
let mut vbus_on_count = 0;
let mut in_u0 = false;
loop {
if vbus_on == false && vbus_on_count == 4 {
crate::println!("vbus on");
usb.init();
usb.start();
vbus_on = true;
in_u0 = false;
} else if usb.pp() == true && vbus_on == false {
vbus_on_count += 1;
delay(100);
} else if usb.pp() == false && vbus_on == true {
crate::println!("20230802 vbus off during while");
usb.stop();
usb.reset();
vbus_on_count = 0;
vbus_on = false;
in_u0 = false;
} else if in_u0 == true && vbus_on == true {
crate::println!("USB stack started");
break;
// crate::println!("Would be uvc_bulk_thread()");
// uvc_bulk_thread();
} else if usb.ccs() == true && vbus_on == true {
crate::println!("enter U0");
in_u0 = true;
}
}
*/
let mut i = 0;
loop {
// wait for interrupt handler to do something
crate::println!("{}", i);
i += 1;
delay(10_000);
// for testing interrupt handler
// let mut irqarray19 = utralib::CSR::new(utralib::utra::irqarray19::HW_IRQARRAY19_BASE as *mut
// u32); irqarray19.wfo(utralib::utra::irqarray19::EV_SOFT_TRIGGER, 0x80);
}
} else {
crate::println!("USB core not allocated, skipping USB test");
}
}
fn delay(quantum: usize) {
use utralib::{CSR, utra};
// abuse the d11ctime timer to create some time-out like thing
let mut d11c = CSR::new(utra::d11ctime::HW_D11CTIME_BASE as *mut u32);
d11c.wfo(utra::d11ctime::CONTROL_COUNT, 333_333); // 1.0ms per interval
let mut polarity = d11c.rf(utra::d11ctime::HEARTBEAT_BEAT);
for _ in 0..quantum {
while polarity == d11c.rf(utra::d11ctime::HEARTBEAT_BEAT) {}
polarity = d11c.rf(utra::d11ctime::HEARTBEAT_BEAT);
}
// we have to split this because we don't know where we caught the previous interval
if quantum == 1 {
while polarity == d11c.rf(utra::d11ctime::HEARTBEAT_BEAT) {}
}
}
fn get_status_request(this: &mut CorigineUsb, request_type: u8, index: u16) {
let ep0_buf = unsafe {
core::slice::from_raw_parts_mut(
this.ep0_buf.load(Ordering::SeqCst) as *mut u8,
CRG_UDC_EP0_REQBUFSIZE,
)
};
let mut status_val: u32 = 0;
let recipient = request_type & 0x1f;
let ep_num = index & 0x7f;
let ep_dir = if index & 0x80 != 0 { USB_SEND } else { USB_RECV };
match recipient {
USB_RECIP_DEVICE => {
status_val |= 0x1;
ep0_buf[0] = status_val as u8;
this.ep0_send(ep0_buf.as_ptr() as usize, 2, 0);
}
USB_RECIP_INTERFACE => {
ep0_buf[0] = 0;
ep0_buf[1] = 0;
this.ep0_send(ep0_buf.as_ptr() as usize, 2, 0);
}
USB_RECIP_ENDPOINT => {
if this.is_halted(ep_num as u8, ep_dir) {
ep0_buf[0] = 1;
this.ep0_send(ep0_buf.as_ptr() as usize, 2, 0);
} else {
ep0_buf[0] = 0;
this.ep0_send(ep0_buf.as_ptr() as usize, 2, 0);
}
}
_ => {
this.ep_halt(0, USB_RECV);
}
}
}
fn handle_event(this: &mut CorigineUsb, event_trb: &mut EventTrbS) -> CrgEvent {
crate::println!("handle_event: {:x?}", event_trb);
let pei = event_trb.get_endpoint_id();
let ep_num = pei >> 1;
let udc_ep = &mut this.udc_ep[pei as usize];
let mut ret = CrgEvent::None;
match event_trb.get_trb_type() {
TrbType::EventPortStatusChange => {
let portsc_val = this.csr.r(PORTSC);
this.csr.wo(PORTSC, portsc_val);
// this.print_status(portsc_val);
let portsc = PortSc(portsc_val);
crate::println!("{:?}", portsc);
if portsc.prc() && !portsc.pr() {
crate::println!("update_current_speed() - reset done");
this.update_current_speed();
}
if portsc.csc() && portsc.ppc() && portsc.pp() && portsc.ccs() {
crate::println!("update_current_speed() - cable connect");
this.update_current_speed();
}
this.csr.rmwf(EVENTCONFIG_SETUP_ENABLE, 1);
}
TrbType::EventTransfer => {
let comp_code =
CompletionCode::try_from(event_trb.dw2.compl_code()).expect("Invalid completion code");
// update the dequeue pointer
crate::println!("event_transfer {:x?}", event_trb);
let deq_pt =
unsafe { (event_trb.dw0 as *mut TransferTrbS).add(1).as_mut().expect("Couldn't deref ptr") };
if deq_pt.get_trb_type() == TrbType::Link {
udc_ep.deq_pt = AtomicPtr::new(udc_ep.first_trb.load(Ordering::SeqCst));
} else {
udc_ep.deq_pt = AtomicPtr::new(deq_pt as *mut TransferTrbS);
}
crate::println!("EventTransfer: comp_code {:?}, PEI {}", comp_code, pei);
let dir = (pei & 1) != 0;
if pei == 0 {
if comp_code == CompletionCode::Success {
// ep0_xfer_complete
if dir == USB_SEND {
ret = CrgEvent::Data(0, 1, 0); // FIXME: this ordering contradicts the `dir` bit, but seems necessary to trigger the next packet send
} else {
ret = CrgEvent::Data(1, 0, 0); // FIXME: this ordering contradicts the `dir` bit, but seems necessary to trigger the next packet send
}
} else {
crate::println!("EP0 unhandled comp_code: {:?}", comp_code);
ret = CrgEvent::None;
}
} else if pei >= 2 {
if comp_code == CompletionCode::Success || comp_code == CompletionCode::ShortPacket {
crate::println!("EP{} xfer event, dir {}", ep_num, if dir { "OUT" } else { "IN" });
// xfer_complete
if let Some(f) = this.udc_ep[pei as usize].completion_handler {
// so unsafe. so unsafe. We're counting on the hardware to hand us a raw pointer
// that isn't corrupted.
let p_trb = unsafe { &*(event_trb.dw0 as *const TransferTrbS) };
f(this, p_trb.dplo as usize, p_trb.dw2.0, 0);
}
} else if comp_code == CompletionCode::MissedServiceError {
crate::println!("MissedServiceError");
} else {
crate::println!("EventTransfer {:?} event not handled", comp_code);
}
}
}
TrbType::SetupPkt => {
let mut setup_storage = [0u8; 8];
setup_storage.copy_from_slice(&event_trb.get_raw_setup());
this.setup = Some(setup_storage);
this.setup_tag = event_trb.get_setup_tag();
crate::println!(" handle_setup_pkt {:x?}, {:x}", setup_storage, this.setup_tag);
let mut setup_pkt = CtrlRequest::default();
setup_pkt.as_mut().copy_from_slice(&setup_storage);
let w_value = setup_pkt.w_value;
let w_index = setup_pkt.w_index;
let w_length = setup_pkt.w_length;
crate::println!(
" b_request={:x}, b_request_type={:x}, w_value={:04x}, w_index=0x{:x}, w_length={}",
setup_pkt.b_request,
setup_pkt.b_request_type,
w_value,
w_index,
w_length
);
if (setup_pkt.b_request_type & USB_TYPE_MASK) == USB_TYPE_STANDARD {
match setup_pkt.b_request {
USB_REQ_GET_STATUS => {
crate::println!("USB_REQ_GET_STATUS");
get_status_request(this, setup_pkt.b_request_type, w_index);
}
USB_REQ_SET_ADDRESS => {
crate::println!("USB_REQ_SET_ADDRESS: {}", w_value);
this.set_addr(w_value as u8, CRG_INT_TARGET);
}
USB_REQ_SET_SEL => {
crate::println!("USB_REQ_SET_SEL");
this.ep0_receive(this.ep0_buf.load(Ordering::SeqCst) as usize, w_length as usize, 0);
delay(100);
/* do set sel */
crate::println!("SEL_VALUE NOT HANDLED");
/*
crg_udc->sel_value.u1_sel_value = *ep0_buf;
crg_udc->sel_value.u1_pel_value = *(ep0_buf+1);
crg_udc->sel_value.u2_sel_value = *(uint16_t*)(ep0_buf+2);
crg_udc->sel_value.u2_pel_value = *(uint16_t*)(ep0_buf+4);
*/
}
USB_REQ_SET_ISOCH_DELAY => {
crate::println!("USB_REQ_SET_ISOCH_DELAY");
/* do set isoch delay */
this.ep0_send(0, 0, 0);
}
USB_REQ_CLEAR_FEATURE => {
crate::println!("USB_REQ_CLEAR_FEATURE");
crate::println!("*** UNSUPPORTED ***");
/* do clear feature */
// clear_feature_request(setup_pkt.b_request_type, w_index, w_value);
}
USB_REQ_SET_FEATURE => {
crate::println!("USB_REQ_SET_FEATURE\r\n");
crate::println!("*** UNSUPPORTED ***");
/* do set feature */
/*
if crg_udc_get_device_state() == USB_STATE_CONFIGURED {
set_feature_request(setup_pkt.b_request_type, w_index, w_value);
} else {
crg_udc_ep_halt(0, USB_RECV);
}
*/
}
USB_REQ_SET_CONFIGURATION => {
crate::println!("USB_REQ_SET_CONFIGURATION");
let mut pass = false;
if w_value == 0 {
this.set_device_state(UsbDeviceState::Address);
} else if w_value == 1 {
this.set_device_state(UsbDeviceState::Configured);
} else {
this.ep_halt(0, USB_RECV);
pass = true;
}
if !pass {
this.assign_completion_handler(usb_ep1_bulk_in_complete, 1, USB_SEND);
this.assign_completion_handler(usb_ep1_bulk_out_complete, 1, USB_RECV);
this.ep_enable(1, USB_SEND, 64, EpType::BulkOutbound);
this.ep_enable(1, USB_RECV, 64, EpType::BulkInbound);
this.bulk_xfer(1, USB_RECV, this.cbw_ptr(), 31, 0, 0);
unsafe { UMS_STATE = UmsState::CommandPhase };
this.ep0_send(0, 0, 0);
}
}
USB_REQ_GET_DESCRIPTOR => {
crate::println!("USB_REQ_GET_DESCRIPTOR");
get_descriptor_request(this, w_value, w_index as usize, w_length as usize);
}
USB_REQ_GET_CONFIGURATION => {
crate::println!("USB_REQ_GET_CONFIGURATION");
let ep0_buf = unsafe {
core::slice::from_raw_parts_mut(
this.ep0_buf.load(Ordering::SeqCst) as *mut u8,
CRG_UDC_EP0_REQBUFSIZE,
)
};
if this.get_device_state() != UsbDeviceState::Configured {
ep0_buf[0] = 0;
} else {
ep0_buf[0] = 1
}
this.ep0_send(ep0_buf.as_ptr() as usize, 1, 0);
}
USB_REQ_SET_INTERFACE => {
crate::println!("USB_REQ_SET_INTERFACE");
this.cur_interface_num = (w_value & 0xF) as u8;
crate::println!("USB_REQ_SET_INTERFACE altsetting {}", this.cur_interface_num);
this.ep0_send(0, 0, 0);
}
USB_REQ_GET_INTERFACE => {
crate::println!("USB_REQ_GET_INTERFACE");
let ep0_buf = unsafe {
core::slice::from_raw_parts_mut(
this.ep0_buf.load(Ordering::SeqCst) as *mut u8,
CRG_UDC_EP0_REQBUFSIZE,
)
};
ep0_buf[0] = this.cur_interface_num;
this.ep0_send(ep0_buf.as_ptr() as usize, 1, 0);
}
_ => {
crate::println!(
"USB_REQ default b_request=0x{:x}, b_request_type=0x{:x}",
setup_pkt.b_request,
setup_pkt.b_request_type
);
this.ep_halt(0, USB_RECV);
}
}
} else if (setup_pkt.b_request_type & USB_TYPE_MASK) == USB_TYPE_CLASS {
match setup_pkt.b_request {
0xff => {
crate::println!("Mass Storage Reset\r\n");
if (0 == w_value)
&& (InterfaceDescriptor::default_mass_storage().b_interface_number
== w_index as u8)
&& (0 == w_length)
{
this.ep_unhalt(1, USB_SEND);
this.ep_unhalt(1, USB_RECV);
this.ep_enable(1, USB_SEND, 64, EpType::BulkOutbound);
this.ep_enable(1, USB_RECV, 64, EpType::BulkInbound);
unsafe { UMS_STATE = UmsState::CommandPhase };
this.bulk_xfer(1, USB_RECV, this.cbw_ptr(), 31, 0, 0);
//crg_udc_ep0_status(false,0);
this.ep0_send(0, 0, 0);
} else {
this.ep_halt(0, USB_RECV);
}
}
0xfe => {
crate::println!("Get Max LUN");
if w_index != 0 || w_value != 0 || w_length != 1 {
this.ep_halt(0, USB_RECV);
} else {
let ep0_buf = unsafe {
core::slice::from_raw_parts_mut(
this.ep0_buf.load(Ordering::SeqCst) as *mut u8,
CRG_UDC_EP0_REQBUFSIZE,
)
};
ep0_buf[0] = 0;
this.ep0_send(ep0_buf.as_ptr() as usize, 1, 0);
}
}
_ => {
crate::println!("Unhandled!");
}
}
} else {
this.ep_halt(0, USB_RECV);
}
ret = CrgEvent::Data(0, 0, 1);
}
TrbType::DataStage => {
panic!("data stage needs handling");
}
_ => {
crate::println!("Unexpected trb_type {:?}", event_trb.get_trb_type());
}
}
ret
}

View file

@ -0,0 +1,235 @@
use cramium_hal::usb::utra::*;
use riscv::register::{mcause, mie, mstatus, vexriscv::mim, vexriscv::mip};
use super::*;
pub(crate) fn enable_irq(irq_no: usize) {
// Note that the vexriscv "IRQ Mask" register is inverse-logic --
// that is, setting a bit in the "mask" register unmasks (i.e. enables) it.
mim::write(mim::read() | (1 << irq_no));
}
pub(crate) fn irq_setup() {
unsafe {
#[rustfmt::skip]
core::arch::asm!(
// stop delegating
"li t0, 0x0",
"csrw mideleg, t0",
"csrw medeleg, t0",
// Set trap handler, which will be called
// on interrupts and cpu faults
"la t0, _start_trap", // this first one forces the nop sled symbol to be generated
"la t0, _start_trap_aligned", // this is the actual target
"csrw mtvec, t0",
);
}
// enable IRQ handling
mim::write(0x0); // first make sure everything is disabled, so we aren't OR'ing in garbage
// must enable external interrupts on the CPU for any of the above to matter
unsafe { mie::set_mext() };
unsafe { mstatus::set_mie() };
}
#[export_name = "_start_trap"]
// #[repr(align(4))] // can't do this yet.
#[inline(never)]
pub unsafe extern "C" fn _start_trap() -> ! {
loop {
// install a NOP sled before _start_trap() until https://github.com/rust-lang/rust/issues/82232 is stable
core::arch::asm!("nop", "nop", "nop", "nop");
#[export_name = "_start_trap_aligned"]
pub unsafe extern "C" fn _start_trap_aligned() {
#[rustfmt::skip]
core::arch::asm!(
"csrw mscratch, sp",
"li sp, 0x610FF000", // scratch page: one page below the disk start
"sw x1, 0*4(sp)",
// Skip SP for now
"sw x3, 2*4(sp)",
"sw x4, 3*4(sp)",
"sw x5, 4*4(sp)",
"sw x6, 5*4(sp)",
"sw x7, 6*4(sp)",
"sw x8, 7*4(sp)",
"sw x9, 8*4(sp)",
"sw x10, 9*4(sp)",
"sw x11, 10*4(sp)",
"sw x12, 11*4(sp)",
"sw x13, 12*4(sp)",
"sw x14, 13*4(sp)",
"sw x15, 14*4(sp)",
"sw x16, 15*4(sp)",
"sw x17, 16*4(sp)",
"sw x18, 17*4(sp)",
"sw x19, 18*4(sp)",
"sw x20, 19*4(sp)",
"sw x21, 20*4(sp)",
"sw x22, 21*4(sp)",
"sw x23, 22*4(sp)",
"sw x24, 23*4(sp)",
"sw x25, 24*4(sp)",
"sw x26, 25*4(sp)",
"sw x27, 26*4(sp)",
"sw x28, 27*4(sp)",
"sw x29, 28*4(sp)",
"sw x30, 29*4(sp)",
"sw x31, 30*4(sp)",
// Save MEPC
"csrr t0, mepc",
"sw t0, 31*4(sp)",
// Finally, save SP
"csrr t0, mscratch",
"sw t0, 1*4(sp)",
// Restore a default stack pointer
"li sp, 0x610FF000", /* builds down from scratch page */
// Note that registers $a0-$a7 still contain the arguments
"j _start_trap_rust",
// Note to self: trying to assign the scratch and default pages using in(reg) syntax
// clobbers the `a0` register and places the initialization outside of the handler loop
// and there seems to be no way to refer directly to a symbol? the `sym` directive wants
// to refer to an address, not a constant.
);
}
_start_trap_aligned();
core::arch::asm!("nop", "nop", "nop", "nop");
}
}
#[export_name = "_resume_context"]
#[inline(never)]
pub unsafe extern "C" fn _resume_context(registers: u32) -> ! {
#[rustfmt::skip]
core::arch::asm!(
"move sp, {registers}",
"lw x1, 0*4(sp)",
// Skip SP for now
"lw x3, 2*4(sp)",
"lw x4, 3*4(sp)",
"lw x5, 4*4(sp)",
"lw x6, 5*4(sp)",
"lw x7, 6*4(sp)",
"lw x8, 7*4(sp)",
"lw x9, 8*4(sp)",
"lw x10, 9*4(sp)",
"lw x11, 10*4(sp)",
"lw x12, 11*4(sp)",
"lw x13, 12*4(sp)",
"lw x14, 13*4(sp)",
"lw x15, 14*4(sp)",
"lw x16, 15*4(sp)",
"lw x17, 16*4(sp)",
"lw x18, 17*4(sp)",
"lw x19, 18*4(sp)",
"lw x20, 19*4(sp)",
"lw x21, 20*4(sp)",
"lw x22, 21*4(sp)",
"lw x23, 22*4(sp)",
"lw x24, 23*4(sp)",
"lw x25, 24*4(sp)",
"lw x26, 25*4(sp)",
"lw x27, 26*4(sp)",
"lw x28, 27*4(sp)",
"lw x29, 28*4(sp)",
"lw x30, 29*4(sp)",
"lw x31, 30*4(sp)",
// Restore SP
"lw x2, 1*4(sp)",
"mret",
registers = in(reg) registers,
);
loop {}
}
#[export_name = "_start_trap_rust"]
pub extern "C" fn trap_handler(
_a0: usize,
_a1: usize,
_a2: usize,
_a3: usize,
_a4: usize,
_a5: usize,
_a6: usize,
_a7: usize,
) -> ! {
let mc: mcause::Mcause = mcause::read();
crate::println!("it's a trap! 0x{:x}", mc.bits());
// 2 is illegal instruction
if mc.bits() == 2 {
crate::abort();
} else if mc.bits() == 0x8000_000B {
// external interrupt. find out which ones triggered it, and clear the source.
let irqs_pending = mip::read();
if (irqs_pending & (1 << utralib::utra::irqarray1::IRQARRAY1_IRQ)) != 0 {
// handle USB interrupt
unsafe {
if let Some(ref mut usb_ref) = USB {
let usb = &mut *core::ptr::addr_of_mut!(*usb_ref);
let pending = usb.irq_csr.r(utralib::utra::irqarray1::EV_PENDING);
let status = usb.csr.r(USBSTS);
// self.print_status(status);
if (status & usb.csr.ms(USBSTS_SYSTEM_ERR, 1)) != 0 {
crate::println!("System error");
usb.csr.wfo(USBSTS_SYSTEM_ERR, 1);
crate::println!("USBCMD: {:x}", usb.csr.r(USBCMD));
} else {
if (status & usb.csr.ms(USBSTS_EINT, 1)) != 0 {
// from udc_handle_interrupt
let mut ret = cramium_hal::usb::driver::CrgEvent::None;
let status = usb.csr.r(USBSTS);
// self.print_status(status);
let result = if (status & usb.csr.ms(USBSTS_SYSTEM_ERR, 1)) != 0 {
crate::println!("System error");
usb.csr.wfo(USBSTS_SYSTEM_ERR, 1);
crate::println!("USBCMD: {:x}", usb.csr.r(USBCMD));
cramium_hal::usb::driver::CrgEvent::Error
} else {
if (status & usb.csr.ms(USBSTS_EINT, 1)) != 0 {
usb.csr.wfo(USBSTS_EINT, 1);
// divert to the loader-based event ring handler
ret = usb.process_event_ring(); // there is only one event ring
}
ret
};
crate::println!("Result: {:?}", result);
}
if usb.csr.rf(IMAN_IE) != 0 {
usb.csr.rmwf(IMAN_IE, 1);
}
}
// clear pending
usb.irq_csr.wo(utralib::utra::irqarray1::EV_PENDING, pending);
// re-enable interrupts
usb.irq_csr.wfo(utralib::utra::irqarray1::EV_ENABLE_USBC_DUPE, 1);
}
}
}
if (irqs_pending & (1 << 19)) != 0 {
// handle irq19 sw trigger test
let mut irqarray19 = utralib::CSR::new(utralib::utra::irqarray19::HW_IRQARRAY19_BASE as *mut u32);
let pending = irqarray19.r(utralib::utra::irqarray19::EV_PENDING);
crate::println!("pending {:x}", (pending << 16 | 19)); // encode the irq bank number and bit number as [bit | bank]
irqarray19.wo(utralib::utra::irqarray19::EV_PENDING, pending);
// software interrupt should not require a 0-write to reset it
}
} else {
crate::abort();
}
// re-enable interrupts
unsafe {
#[rustfmt::skip]
core::arch::asm!(
"csrr t0, mstatus",
"ori t0, t0, 3",
"csrw mstatus, t0",
);
}
unsafe { mie::set_mext() };
unsafe { _resume_context(SCRATCH_PAGE as u32) };
}

View file

@ -0,0 +1,200 @@
use core::sync::atomic::Ordering;
use cramium_hal::usb::driver::CorigineUsb;
use cramium_hal::usb::driver::*;
use super::*;
// MBR template
// 0x0b~0x0C 2 bytes means block size, default 0x200 bytes
// 0x20~0x23 4 bytes means block number, default 0x400 block
#[rustfmt::skip] // keep this in 16-byte width
pub(crate) const MBR_TEMPLATE: [u8; 512] = [
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x20, 0x01, 0x00,
0x02, 0x00, 0x02, 0x00, 0x00, 0xF8, 0x00, 0x01, 0x3f, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x80, 0x00, 0x29, 0x72, 0x1a, 0x65, 0xA4, 0x4E, 0x4F, 0x20, 0x4E, 0x41,
0x4D, 0x45, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x33, 0xC9,
0x8E, 0xD1, 0xBC, 0xF0, 0x7B, 0x8E, 0xD9, 0xB8, 0x00, 0x20, 0x8E, 0xC0, 0xFC, 0xBD, 0x00, 0x7C,
0x38, 0x4E, 0x24, 0x7D, 0x24, 0x8B, 0xC1, 0x99, 0xE8, 0x3C, 0x01, 0x72, 0x1C, 0x83, 0xEB, 0x3A,
0x66, 0xA1, 0x1C, 0x7C, 0x26, 0x66, 0x3B, 0x07, 0x26, 0x8A, 0x57, 0xFC, 0x75, 0x06, 0x80, 0xCA,
0x02, 0x88, 0x56, 0x02, 0x80, 0xC3, 0x10, 0x73, 0xEB, 0x33, 0xC9, 0x8A, 0x46, 0x10, 0x98, 0xF7,
0x66, 0x16, 0x03, 0x46, 0x1C, 0x13, 0x56, 0x1E, 0x03, 0x46, 0x0E, 0x13, 0xD1, 0x8B, 0x76, 0x11,
0x60, 0x89, 0x46, 0xFC, 0x89, 0x56, 0xFE, 0xB8, 0x20, 0x00, 0xF7, 0xE6, 0x8B, 0x5E, 0x0B, 0x03,
0xC3, 0x48, 0xF7, 0xF3, 0x01, 0x46, 0xFC, 0x11, 0x4E, 0xFE, 0x61, 0xBF, 0x00, 0x00, 0xE8, 0xE6,
0x00, 0x72, 0x39, 0x26, 0x38, 0x2D, 0x74, 0x17, 0x60, 0xB1, 0x0B, 0xBE, 0xA1, 0x7D, 0xF3, 0xA6,
0x61, 0x74, 0x32, 0x4E, 0x74, 0x09, 0x83, 0xC7, 0x20, 0x3B, 0xFB, 0x72, 0xE6, 0xEB, 0xDC, 0xA0,
0xFB, 0x7D, 0xB4, 0x7D, 0x8B, 0xF0, 0xAC, 0x98, 0x40, 0x74, 0x0C, 0x48, 0x74, 0x13, 0xB4, 0x0E,
0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xEF, 0xA0, 0xFD, 0x7D, 0xEB, 0xE6, 0xA0, 0xFC, 0x7D, 0xEB,
0xE1, 0xCD, 0x16, 0xCD, 0x19, 0x26, 0x8B, 0x55, 0x1A, 0x52, 0xB0, 0x01, 0xBB, 0x00, 0x00, 0xE8,
0x3B, 0x00, 0x72, 0xE8, 0x5B, 0x8A, 0x56, 0x24, 0xBE, 0x0B, 0x7C, 0x8B, 0xFC, 0xC7, 0x46, 0xF0,
0x3D, 0x7D, 0xC7, 0x46, 0xF4, 0x29, 0x7D, 0x8C, 0xD9, 0x89, 0x4E, 0xF2, 0x89, 0x4E, 0xF6, 0xC6,
0x06, 0x96, 0x7D, 0xCB, 0xEA, 0x03, 0x00, 0x00, 0x20, 0x0F, 0xB6, 0xC8, 0x66, 0x8B, 0x46, 0xF8,
0x66, 0x03, 0x46, 0x1C, 0x66, 0x8B, 0xD0, 0x66, 0xC1, 0xEA, 0x10, 0xEB, 0x5E, 0x0F, 0xB6, 0xC8,
0x4A, 0x4A, 0x8A, 0x46, 0x0D, 0x32, 0xE4, 0xF7, 0xE2, 0x03, 0x46, 0xFC, 0x13, 0x56, 0xFE, 0xEB,
0x4A, 0x52, 0x50, 0x06, 0x53, 0x6A, 0x01, 0x6A, 0x10, 0x91, 0x8B, 0x46, 0x18, 0x96, 0x92, 0x33,
0xD2, 0xF7, 0xF6, 0x91, 0xF7, 0xF6, 0x42, 0x87, 0xCA, 0xF7, 0x76, 0x1A, 0x8A, 0xF2, 0x8A, 0xE8,
0xC0, 0xCC, 0x02, 0x0A, 0xCC, 0xB8, 0x01, 0x02, 0x80, 0x7E, 0x02, 0x0E, 0x75, 0x04, 0xB4, 0x42,
0x8B, 0xF4, 0x8A, 0x56, 0x24, 0xCD, 0x13, 0x61, 0x61, 0x72, 0x0B, 0x40, 0x75, 0x01, 0x42, 0x03,
0x5E, 0x0B, 0x49, 0x75, 0x06, 0xF8, 0xC3, 0x41, 0xBB, 0x00, 0x00, 0x60, 0x66, 0x6A, 0x00, 0xEB,
0xB0, 0x42, 0x4F, 0x4F, 0x54, 0x4D, 0x47, 0x52, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x0A, 0x52, 0x65,
0x6D, 0x6F, 0x76, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74,
0x68, 0x65, 0x72, 0x20, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x2E, 0xFF, 0x0D, 0x0A, 0x44, 0x69, 0x73,
0x6B, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0xFF, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20,
0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61,
0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xCB, 0xD8, 0x55, 0xAA
];
pub(crate) const MASS_STORAGE_EPADDR_IN: u8 = 0x81;
pub(crate) const MASS_STORAGE_EPADDR_OUT: u8 = 0x01;
pub fn get_descriptor_request(this: &mut CorigineUsb, value: u16, _index: usize, length: usize) {
crate::println!(
"ifram: {:x}, ep0_ptr: {:x}",
this.ifram_base_ptr,
this.ep0_buf.load(Ordering::SeqCst) as usize
);
let ep0_buf = unsafe {
core::slice::from_raw_parts_mut(
this.ep0_buf.load(Ordering::SeqCst) as *mut u8,
CRG_UDC_EP0_REQBUFSIZE,
)
};
match (value >> 8) as u8 {
USB_DT_DEVICE => {
crate::println!("USB_DT_DEVICE");
let mut device_descriptor = DeviceDescriptor::default_mass_storage();
device_descriptor.b_max_packet_size0 = 64;
device_descriptor.b_cd_usb = 0x0210;
let len = length.min(core::mem::size_of::<DeviceDescriptor>());
ep0_buf[..len].copy_from_slice(&device_descriptor.as_ref()[..len]);
crate::println!("ptr: {:x}, len: {}", this.ep0_buf.load(Ordering::SeqCst) as usize, len);
crate::println!("dd: {:x?}", device_descriptor.as_ref());
crate::println!("buf: {:x?}", &ep0_buf[..len]);
this.ep0_send(this.ep0_buf.load(Ordering::SeqCst) as usize, len, 0);
}
USB_DT_DEVICE_QUALIFIER => {
crate::println!("USB_DT_DEVICE_QUALIFIER");
let qualifier_descriptor = QualifierDescriptor::default_mass_storage();
let len = length.min(core::mem::size_of::<QualifierDescriptor>());
ep0_buf[..len].copy_from_slice(&qualifier_descriptor.as_ref()[..len]);
this.ep0_send(this.ep0_buf.load(Ordering::SeqCst) as usize, len, 0);
}
USB_DT_OTHER_SPEED_CONFIG => {
crate::println!("USB_DT_OTHER_SPEED_CONFIG\r\n");
crate::println!("*** UNHANDLED ***");
}
USB_DT_CONFIG => {
crate::println!("USB_DT_CONFIG\r\n");
let total_length = size_of::<ConfigDescriptor>()
+ size_of::<InterfaceDescriptor>()
+ size_of::<EndpointDescriptor>() * 2;
let config = ConfigDescriptor::default_mass_storage(total_length as u16);
let interface = InterfaceDescriptor::default_mass_storage();
let ep_in = EndpointDescriptor::default_mass_storage(MASS_STORAGE_EPADDR_IN, 64);
let ep_out = EndpointDescriptor::default_mass_storage(MASS_STORAGE_EPADDR_OUT, 64);
let response: [&[u8]; 4] = [config.as_ref(), interface.as_ref(), ep_in.as_ref(), ep_out.as_ref()];
let flattened = response.iter().flat_map(|slice| slice.iter().copied());
for (dst, src) in ep0_buf.iter_mut().zip(flattened) {
*dst = src
}
let buffsize = total_length.min(length);
this.ep0_send(this.ep0_buf.load(Ordering::SeqCst) as usize, buffsize, 0);
}
USB_DT_STRING => {
crate::println!("USB_DT_STRING\r\n");
let id = (value & 0xFF) as u8;
let len = if id == 0 {
// index 0 is the language type. This is the hard-coded response for "English".
ep0_buf[..4].copy_from_slice(&[4, USB_DT_STRING, 9, 4]);
this.ep0_send(this.ep0_buf.load(Ordering::SeqCst) as usize, 4, 0);
4
} else {
let s = match id {
1 => MANUFACTURER,
2 => PRODUCT,
_ => SERIAL,
};
// strings are utf16-le encoded words. Manually pack them.
let len = 2 + s.len() * 2; // 2 bytes for header + string data
ep0_buf[0] = len as u8;
ep0_buf[1] = USB_DT_STRING;
// this code fails if the string isn't simple ASCII. Yes, we could
// embed idk unicode emoji if I coded this better, but I ask you, WHY‽
for (dst, &src) in ep0_buf[2..].chunks_exact_mut(2).zip(s.as_bytes()) {
dst.copy_from_slice(&(src as u16).to_le_bytes());
}
len
};
let buffsize = length.min(len);
this.ep0_send(this.ep0_buf.load(Ordering::SeqCst) as usize, buffsize, 0);
}
USB_DT_BOS => {
crate::println!("USB_DT_BOS");
crate::println!("Not supported, repsonding with stall");
this.ep_halt(0, USB_RECV);
}
_ => {
crate::println!("UNHANDLED SETUP: 0x{:x}", value >> 8);
this.ep_halt(0, USB_RECV);
}
}
}
pub fn usb_ep1_bulk_out_complete(_this: &mut CorigineUsb, _buf_addr: usize, _info: u32, _error: u8) {
crate::println!("bulk_out_complete callback TODO");
/*
let length = info & 0xFFFF;
let buf = unsafe {core::slice::from_raw_parts(buf_addr as *const u8, info as usize & 0xFFFF)};
let cbw = unsafe { core::slice::from_raw_parts_mut(this.cbw_ptr() as *mut u8, CRG_UDC_APP_BUF_LEN) };
if unsafe{UmsState::CommandPhase == UMS_STATE} && (length == 31) { //CBW
memcpy(cbw, buf, 31);
if(cbw->Signature == BULK_CBW_SIG) {
csw->Signature = BULK_CSW_SIG;
csw->Tag = cbw->Tag;
_process_mass_storage_command(cbw);
invalid_cbw = 0;
}
else {
crg_udc_ep_halt(1, USB_SEND);
crg_udc_ep_halt(1, USB_RECV);
invalid_cbw = 1;
}
}
else if ((UMS_STATE_COMMAND_PHASE == ums_state) && (length != 31)) {
crg_udc_ep_halt(1, USB_SEND);
crg_udc_ep_halt(1, USB_RECV);
invalid_cbw = 1;
}
else if(UMS_STATE_DATA_PHASE == ums_state) { //DATA
csw->Residue = 0;
csw->Status = 0;
crg_udc_bulk_xfer(1, USB_SEND, (uint8_t *)csw, 13, 0, 0);
ums_state = UMS_STATE_STATUS_PHASE;
}
*/
}
pub fn usb_ep1_bulk_in_complete(_this: &mut CorigineUsb, _buf_addr: usize, _info: u32, _error: u8) {
crate::println!("bulk_in_complete callback TODO");
/*
uint32_t length = info & 0xFFFF;
if(UMS_STATE_DATA_PHASE == ums_state) { //DATA
crg_udc_bulk_xfer(1, USB_SEND, (uint8_t *)csw, 13, 0, 0);
ums_state = UMS_STATE_STATUS_PHASE;
}
else if(UMS_STATE_STATUS_PHASE == ums_state && length == 13) //CSW
{
crg_udc_bulk_xfer(1, USB_RECV, (uint8_t *)cbw, 31, 0, 0);
ums_state = UMS_STATE_COMMAND_PHASE;
}
*/
}

View file

@ -0,0 +1,329 @@
mod driver;
mod irq;
mod mass_storage;
pub use driver::*;
pub use irq::*;
pub use mass_storage::*;
// locate the "disk" at 1MiB -- middle of the SRAM region. This can be
// fine-tuned later.
const RAMDISK_ADDRESS: usize = utralib::HW_SRAM_MEM + 1024 * 1024;
const RAMDISK_LEN: usize = 512 * 1024; // 512k of RAM allocated to "disk"
const SECTOR_SIZE: u16 = 512;
// Note that the trap handler is just placed one page below this, and it
// needs to be manually updated in the assembly because we can't refer to
// consts in that snippet of assembly. That handler also needs a default
// stack area, which is right below that spare page.
const SCRATCH_PAGE: usize = RAMDISK_ADDRESS - 4096;
#[allow(dead_code)] // this reminds us there are two places this has to be changed in assembly-land
const EXCEPTION_STACK: usize = SCRATCH_PAGE;
const USB_TYPE_MASK: u8 = 0x03 << 5;
const USB_TYPE_STANDARD: u8 = 0x00 << 5;
const USB_TYPE_CLASS: u8 = 0x01 << 5;
#[allow(dead_code)]
const USB_TYPE_VENDOR: u8 = 0x02 << 5;
#[allow(dead_code)]
const USB_TYPE_RESERVED: u8 = 0x03 << 5;
/*
* USB recipients, the third of three bRequestType fields
*/
#[allow(dead_code)]
const USB_RECIP_MASK: u8 = 0x1f;
const USB_RECIP_DEVICE: u8 = 0x00;
const USB_RECIP_INTERFACE: u8 = 0x01;
const USB_RECIP_ENDPOINT: u8 = 0x02;
#[allow(dead_code)]
const USB_RECIP_OTHER: u8 = 0x03;
const USB_REQ_GET_STATUS: u8 = 0x00;
const USB_REQ_CLEAR_FEATURE: u8 = 0x01;
const USB_REQ_SET_FEATURE: u8 = 0x03;
const USB_REQ_SET_ADDRESS: u8 = 0x05;
const USB_REQ_GET_DESCRIPTOR: u8 = 0x06;
#[allow(dead_code)]
const USB_REQ_SET_DESCRIPTOR: u8 = 0x07;
const USB_REQ_GET_CONFIGURATION: u8 = 0x08;
const USB_REQ_SET_CONFIGURATION: u8 = 0x09;
const USB_REQ_GET_INTERFACE: u8 = 0x0A;
const USB_REQ_SET_INTERFACE: u8 = 0x0B;
#[allow(dead_code)]
const USB_REQ_SYNCH_FRAME: u8 = 0x0C;
const USB_REQ_SET_SEL: u8 = 0x30;
const USB_REQ_SET_ISOCH_DELAY: u8 = 0x31;
const USB_DT_DEVICE: u8 = 0x01;
const USB_DT_CONFIG: u8 = 0x02;
const USB_DT_STRING: u8 = 0x03;
#[allow(dead_code)]
const USB_DT_INTERFACE: u8 = 0x04;
const USB_DT_ENDPOINT: u8 = 0x05;
const USB_DT_DEVICE_QUALIFIER: u8 = 0x06;
const USB_DT_OTHER_SPEED_CONFIG: u8 = 0x07;
#[allow(dead_code)]
const USB_DT_INTERFACE_POWER: u8 = 0x08;
/* these are from a minor usb 2.0 revision (ECN) */
#[allow(dead_code)]
const USB_DT_OTG: u8 = 0x09;
#[allow(dead_code)]
const USB_DT_DEVICE_CAPABILITY: u8 = 0x10;
#[allow(dead_code)]
const USB_DT_DEBUG: u8 = 0x0a;
#[allow(dead_code)]
const USB_DT_INTERFACE_ASSOCIATION: u8 = 0x0b;
#[allow(dead_code)]
const USB_DT_BOS: u8 = 0x0f;
/* From the T10 UAS specification */
#[allow(dead_code)]
const USB_DT_PIPE_USAGE: u8 = 0x24;
/* From the USB 3.0 spec */
#[allow(dead_code)]
const USB_DT_SS_ENDPOINT_COMP: u8 = 0x30;
/* From the USB 3.1 spec */
#[allow(dead_code)]
const USB_DT_SSP_ISOC_ENDPOINT_COMP: u8 = 0x31;
#[allow(dead_code)]
#[repr(i32)]
pub(crate) enum UmsState {
// Thesea ren't used
CommandPhase = -10,
DataPhase,
StatusPhase,
Idle = 0,
AbortBulkOut,
Reset,
InterfaceChange,
ConfigChange,
Disconnect,
Exit,
Terminated,
}
#[allow(dead_code)]
#[repr(packed)]
struct DeviceDescriptor {
pub b_length: u8,
pub b_descriptor_type: u8,
pub b_cd_usb: u16,
pub b_device_class: u8,
pub b_device_sub_class: u8,
pub b_device_protocol: u8,
pub b_max_packet_size0: u8,
pub id_vendor: u16,
pub id_product: u16,
pub b_cd_device: u16,
pub i_manufacturer: u8,
pub i_product: u8,
pub i_serial_number: u8,
pub b_num_configurations: u8,
}
const VENDOR_ID: u16 = 0x1209;
const PRODUCT_ID: u16 = 0x3613; // this needs to change! this is the Precursor product ID.
const MANUFACTURER: &'static str = "Bao Semi";
const PRODUCT: &'static str = "SecuriBao";
// no seriously, do this
const SERIAL: &'static str = "TODO";
impl DeviceDescriptor {
pub fn default_mass_storage() -> Self {
Self {
b_length: core::mem::size_of::<Self>() as u8,
b_descriptor_type: USB_DT_DEVICE,
b_cd_usb: 0x0200,
b_device_class: 0,
b_device_sub_class: 0,
b_device_protocol: 0,
b_max_packet_size0: 0x40,
id_vendor: VENDOR_ID,
id_product: PRODUCT_ID,
b_cd_device: 0x0101,
i_manufacturer: 0x01, // string index for manufacturer
i_product: 0x02, // string index for product
i_serial_number: 0x03, // string index for serial number
b_num_configurations: 1,
}
}
}
impl AsRef<[u8]> for DeviceDescriptor {
fn as_ref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self as *const DeviceDescriptor as *const u8,
core::mem::size_of::<DeviceDescriptor>(),
) as &[u8]
}
}
}
/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
#[allow(dead_code)]
#[repr(packed)]
struct QualifierDescriptor {
pub b_length: u8,
pub b_descriptor_type: u8,
pub b_cd_usb: u16,
pub b_device_class: u8,
pub b_device_sub_class: u8,
pub b_device_protocol: u8,
pub b_max_packet_size0: u8,
pub b_num_configurations: u8,
pub b_reserved: u8,
}
impl QualifierDescriptor {
pub fn default_mass_storage() -> Self {
Self {
b_length: 0xA,
b_descriptor_type: 0x6,
b_cd_usb: 0x200,
b_device_class: 0x0,
b_device_sub_class: 0x0,
b_device_protocol: 0x0,
b_max_packet_size0: 0x40,
b_num_configurations: 0x1,
b_reserved: 0x0,
}
}
}
impl AsRef<[u8]> for QualifierDescriptor {
fn as_ref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self as *const QualifierDescriptor as *const u8,
core::mem::size_of::<QualifierDescriptor>(),
) as &[u8]
}
}
}
#[allow(dead_code)]
#[repr(packed)]
struct ConfigDescriptor {
pub b_length: u8,
pub b_descriptor_type: u8,
pub w_total_length: u16,
pub b_num_interfaces: u8,
pub b_configuration_value: u8,
pub i_configuration: u8,
pub bm_attributes: u8,
pub b_max_power: u8,
}
impl ConfigDescriptor {
pub fn default_mass_storage(total_length: u16) -> Self {
ConfigDescriptor {
b_length: core::mem::size_of::<Self>() as u8,
b_descriptor_type: USB_DT_CONFIG,
w_total_length: total_length,
b_num_interfaces: 1,
b_configuration_value: 1,
i_configuration: 0x0,
bm_attributes: 0xC0,
b_max_power: 250,
}
}
}
impl AsRef<[u8]> for ConfigDescriptor {
fn as_ref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self as *const ConfigDescriptor as *const u8,
core::mem::size_of::<ConfigDescriptor>(),
) as &[u8]
}
}
}
#[allow(dead_code)]
#[repr(packed)]
struct InterfaceDescriptor {
pub b_length: u8,
pub b_descriptor_type: u8,
pub b_interface_number: u8,
pub b_alternate_setting: u8,
pub b_num_endpoints: u8,
pub b_interface_class: u8,
pub b_interface_sub_class: u8,
pub b_interface_protocol: u8,
pub i_interface: u8,
}
impl InterfaceDescriptor {
pub fn default_mass_storage() -> Self {
InterfaceDescriptor {
b_length: core::mem::size_of::<Self>() as u8,
b_descriptor_type: USB_DT_CONFIG,
b_interface_number: 0,
b_alternate_setting: 0,
b_num_endpoints: 2,
b_interface_class: 0x08, // mass storage class
b_interface_sub_class: 0x06,
b_interface_protocol: 0x50,
i_interface: 0x0,
}
}
}
impl AsRef<[u8]> for InterfaceDescriptor {
fn as_ref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self as *const InterfaceDescriptor as *const u8,
core::mem::size_of::<InterfaceDescriptor>(),
) as &[u8]
}
}
}
#[allow(dead_code)]
#[repr(packed)]
struct EndpointDescriptor {
b_length: u8,
b_descriptor_type: u8,
b_endpoint_address: u8,
b_m_attributes: u8,
w_max_packet_size: u16,
b_interval: u8,
}
impl EndpointDescriptor {
pub fn default_mass_storage(addr: u8, max_packet_size: u16) -> Self {
EndpointDescriptor {
b_length: core::mem::size_of::<Self>() as u8,
b_descriptor_type: USB_DT_ENDPOINT,
b_endpoint_address: addr,
b_m_attributes: 0x02,
w_max_packet_size: max_packet_size,
b_interval: 0x0,
}
}
}
impl AsRef<[u8]> for EndpointDescriptor {
fn as_ref(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self as *const EndpointDescriptor as *const u8,
core::mem::size_of::<EndpointDescriptor>(),
) as &[u8]
}
}
}
#[repr(C, align(8))]
#[derive(Default)]
struct CtrlRequest {
b_request_type: u8,
b_request: u8,
w_value: u16,
w_index: u16,
w_length: u16,
}
impl AsMut<[u8]> for CtrlRequest {
fn as_mut(&mut self) -> &mut [u8] {
unsafe {
core::slice::from_raw_parts_mut(
self as *const CtrlRequest as *mut u8,
core::mem::size_of::<CtrlRequest>(),
) as &mut [u8]
}
}
}